Server Sided Arm Pointing

Hello everyone!

I’d like to make this system where the player’s arm follows their mouse server-sided. It works well on client side, but unfortunately, when I transition it to server-side like so:

LocalScript

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local event = game:GetService("ReplicatedStorage"):WaitForChild("UpdateArmWeld")

local YAW_MIN = math.rad(-70) 
local YAW_MAX = math.rad(70)
local PITCH_MIN = math.rad(-30)
local PITCH_MAX = math.rad(30)

local plr = Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()

local tool = script.Parent

wait(2)

local function updateArmWeld(message)
	event:FireServer(message)
end

local function rotateArm()
	local hrp = char:WaitForChild("HumanoidRootPart")
	local rShoulder = char:WaitForChild("Torso"):WaitForChild("Right Shoulder")

	local jointWorld = rShoulder.Part0.CFrame * rShoulder.C0

	local dirLocal = jointWorld:PointToObjectSpace(mouse.Hit.Position)

	local yaw = math.atan2(-dirLocal.Z, dirLocal.X) 
	local pitch = math.asin(dirLocal.Unit.Y) 

	local yawClamped = math.clamp(yaw, YAW_MIN, YAW_MAX)
	local pitchClamped = math.clamp(pitch, PITCH_MIN, PITCH_MAX)
	rShoulder.Transform = CFrame.fromOrientation(0, yawClamped, pitchClamped + math.pi/2)
	
	updateArmWeld(rShoulder, yawClamped, pitchClamped)
end

local steppedConn
tool.Equipped:Connect(function()
	steppedConn = RunService.Stepped:Connect(function()
		rotateArm(char)
	end)
end)

tool.Unequipped:Connect(function()
	steppedConn:Disconnect()
end)

Script:

local updateArmWeldEvent = game:GetService("ReplicatedStorage").UpdateArmWeld

wait(2)

updateArmWeldEvent.OnServerEvent:Connect(function(player, rShoulder, yawClamped, pitchClamped)

rShoulder.Transform = CFrame.fromOrientation(0, yawClamped, pitchClamped + math.pi/2)

end)

However, it gives me this error:

Is there any way to fix this?

Thanks for anything!

Edit: (Essentially, I just need to detect when the arm is rotated and mirror that to the server.)

The issue is that you only take in the first argument of the message

I believe you can do it like this though:

local function updateArmWeld(...)
	event:FireServer(...)
end

You could also set it up like this:

local updateArmWeld = event:FireServer

Or you could do it another way:

local function updateArmWeld(rShoulder, yawClamped, pitchClamped)
	event:FireServer(rShoulder, yawClamped, pitchClamped)
end

(not really sure if the second one works, but it’s an idea that popped up)

Now it doesn’t error, but it simply doesn’t show a change.

I think it’s because the server doesn’t have much control over how a character moves, so send this data to the other clients to change for themselves.

I know how to send the information, but how would I change that one specific player’s movement on all clients?

you would just take the player who sent the arm information, pass it along to all clients by FireAllClients()

on clients, they should have a listening function, utilizing the player and given info (if it is the self player then just return and dont do anything), access the character by player.character and change the arm cframe as you normal would on self client

I tried this, firing a RemoteEvent to server, then firing all clients.

LocalScript 1 (The client who rotates arm)

local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local event = game:GetService("ReplicatedStorage"):WaitForChild("Change")

local YAW_MIN = math.rad(-70) 
local YAW_MAX = math.rad(70)
local PITCH_MIN = math.rad(-30)
local PITCH_MAX = math.rad(30)

local plr = Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()

local tool = script.Parent

wait(2)


local function rotateArm()
	local hrp = char:WaitForChild("HumanoidRootPart")
	local rShoulder = char:WaitForChild("Torso"):WaitForChild("Right Shoulder")

	local jointWorld = rShoulder.Part0.CFrame * rShoulder.C0

	local dirLocal = jointWorld:PointToObjectSpace(mouse.Hit.Position)

	local yaw = math.atan2(-dirLocal.Z, dirLocal.X) 
	local pitch = math.asin(dirLocal.Unit.Y) 

	local yawClamped = math.clamp(yaw, YAW_MIN, YAW_MAX)
	local pitchClamped = math.clamp(pitch, PITCH_MIN, PITCH_MAX)
	rShoulder.Transform = CFrame.fromOrientation(0, yawClamped, pitchClamped + math.pi/2)
	
	event:FireServer(rShoulder, yawClamped, pitchClamped)
end

local steppedConn
tool.Equipped:Connect(function()
	steppedConn = RunService.Stepped:Connect(function()
		rotateArm(char)
	end)
end)

tool.Unequipped:Connect(function()
	steppedConn:Disconnect()
end)

ServerScript

local event = game:GetService("ReplicatedStorage"):WaitForChild("Change")

event.OnServerEvent:Connect(function(p, rShoulder, yawClamped, pitchClamped)
	event:FireAllClients(p, yawClamped, pitchClamped)
end)

LocalScript 2 (All clients, in StarterPlayerScripts)

local event = game:GetService("ReplicatedStorage"):WaitForChild("Change")

event.OnClientEvent:Connect(function(p, yawClamped, pitchClamped)
	local rShoulder = p.Character.Torso:WaitForChild("Right Shoulder")
	rShoulder.Transform = CFrame.fromOrientation(0, yawClamped, pitchClamped + math.pi/2)
end)