RemoteFunction receiving wrong CFrame rotation

I’m working on a furniture system where the user can place objects, but when I send the CFrame to server the server gives the wrong rotation, meaning that the object will always be put in the opposite direction

I tried using cf:ToEulerAnglesXYZ() to get rotations and sending cframe position, rx, ry, rz to server, and when I print rx/ry/rz they have the same values in both environments, but when I create the CFrame in the server (with CFrame.new(position) * CFrame.fromEulerAnglesXYZ(rx, ry, rz)) it still giving the same wrong result:

Client

local cf = Model:GetPivot()
local rx, ry, rz =  cf:ToEulerAnglesXYZ()
print(`Client Rotation - rx: {rx} ry: {ry} rz: {rz}`)
print("Client CFrame: " .. tostring(cf))
local result = PlaceRemote:InvokeServer(Model.Name, cf.Position, rx, ry, rz)

Server

PlaceObject.OnServerInvoke = function(player: Player, furnitureName: string, position: Vector3, rx, ry, rz)
	print(`Server Rotation - rx: {rx} ry: {ry} rz: {rz}`) -- Correct rotation
	local cf = CFrame.new(position) * CFrame.fromEulerAnglesXYZ(rx, ry, rz)
	print("Server CFrame: " .. tostring(cf)) -- Gives the wrong rotation
	
	--- ...
end

Why not just use the Model’s Primary Part?

It contains all the positioning info.


PlaceObject.OnServerInvoke = function(player: Player, furnitureName: string, cframe)
	
	MyModel.PrimaryPart.CFrame = cframe
	--- ...
end

y r u being so weird with it, just use cframe not separate, if not, math.rad(180) + [x/y/z]

-- Client
local cf = Model:GetPivot()
print("Client CFrame: " .. tostring(cf))
local result = PlaceRemote:InvokeServer(Model.Name, cf)

-- Server
PlaceObject.OnServerInvoke = function(player: Player, furnitureName: string, cf)
	print("Server CFrame: " .. tostring(cf))
	-- Use the received CFrame to place the object
	-- ...
end

banner

I’ve tried sending directly the PrimaryPart CFrame to server and using SetPrimaryPart on server, gives the same results.

Using CFrame directly in parameter was the first thing that I did. Rotating 180 degrees obviously works but’s kinda a hacky way and I’m curious about why CFrame isn’t replicating correctly through Client → Server

Just curious… the model that the client is rotating… is it a different model than the one that is cloned into the Workspace?

idk could be sum wrong with your network ownership, or how your cloning your model, or where you get them from, like if they don’t have rotation but on the client placing you have rotation, I tried your system real quick on mine and I got nothing wrong.

banner

The same model. Server gets the model from ReplicatedStorage using the name that client gave. Clients also gets the model from the same place (ReplicatedStorage)

This little chunk of code may solve you issue:

-- This code should be placed in a LocalScript under StarterPlayerScripts
local Players = game:GetService("Players")
local ContextActionService = game:GetService("ContextActionService")

local player = Players.LocalPlayer

local function doTeleport(_actionName, inputState, _inputObject)
	local character = player.Character
	if character and character.Parent and inputState == Enum.UserInputState.Begin then
		-- Move the character 10 studs forwards in the direction they're facing
		local currentPivot = character:GetPivot()
		character:PivotTo(currentPivot * CFrame.new(0, 0, -10))
	end
end

ContextActionService:BindAction("Teleport", doTeleport, true, Enum.KeyCode.F)

It is from:


These two lines of code:


local currentPivot = character:GetPivot() – send to server
character:PivotTo(currentPivot * CFrame.new(0, 0, -10)) – use on server

1 Like

Try printing out tostring(CFrame.fromEulerAnglesXYZ(rx, ry, rz))
and this:
Restart studio and make sure everything is up to date.

tostring(CFrame.fromEulerAngles(rx, 0, 0))   -- X
tostring(CFrame.fromEulerAngles(0, ry, 0))  -- Y
tostring(CFrame.fromEulerAngles(0, 0, rz))    -- Z

banner

I feel obligated to point out that both -4.37113883e-08 and -6.18172393e-08 are both effectively zero and that them being rounded to zero is probably due to some quirk on the C++ side.

image

Try changing your code so that you only provide the server with the Position and LookVector of the CFrame, and then reconstruct it that way.

-- Client
local result = PlaceRemote:InvokeServer(Model.Name, cf.Position, cf.LookVector)
-- Server
PlaceObject.OnServerInvoke = function(player: Player, furnitureName: string, position: Vector3, lookVector: Vector3)
	-- also dear god please put some sanity checks in here so you don't get NaN'd
	-- assert position == position, lookVector == lookVector, etc.
	local cf = CFrame.lookAlong(position, lookVector, Vector3.yAxis)
end
2 Likes

Oh, thank you so much! I thought client was sending like -4.371 and -6.181, I didn’t know that they are basically 0.

After some research I discovered that what was causing the object point to wrong direction was actually the MeshPart that had been set to -180 orientation at some point in Studio (My model is a MeshPart with a extra PrimaryPart for hitbox) and setting it back to 0 solve the issue.

The only thing I didn’t understand was the CFrame being different on client and server, but with your explication now it makes total sense, it’s probably just the Improved rotation replication precision in action.

And again, thank you so much!!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.