Serverside character position is different from the client

I made a very bad vaulting script,but when i vault the serverside character position and the clientside character position are completely different,and that breaks a lot of stuff.

I tried searching on forum for that,but couldnt understand anything.

Heres a video of the problem:

(if the video doesnt work then click this link)

And the serverscript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local DebouncePlrs = {}
local StaminaRecoveryDebounce = {}
local StaminaRecoveryValue = 200

-- I am afraid of this thing


local function VisualizeRay(origin,hitposition,brickcolor)
 --[[
	local position = hitposition
	local distance = (origin - position).Magnitude
	local p = Instance.new("Part")
	p.Anchored = true
	p.CanCollide = false
	p.Size = Vector3.new(0.1, 0.1, distance)
	p.CFrame = CFrame.lookAt(position, origin)*CFrame.new(0, 0, -distance/2)
	p.Parent = workspace
	p.Material = Enum.Material.Neon
	p.BrickColor = brickcolor
	p.CanQuery = false
   ]]
	
end



ReplicatedStorage.Events.Movement.Jump.OnServerEvent:Connect(function(plr)
	local char = plr.Character
	local Humanoid = plr.Character.Humanoid
	local HRP = char.HumanoidRootPart
	
	local MaxVaultDistanceFromPart = 13 + 1	
	
	local function Jump() -- if the vaulting requirements are not met then make the player jump with this function

		Humanoid.JumpPower = 20


		Humanoid.Jump = true
		task.wait(0.5)

		Humanoid.JumpPower = 0
	end
	
	local RayParams = RaycastParams.new()
	RayParams.FilterType = Enum.RaycastFilterType.Exclude
	RayParams.FilterDescendantsInstances  = {char,char["Left Arm"],char["Left Leg"],char["Right Leg"],char["Right Arm"],char["Head"],char["Camera"] }
	
	
	
	
	if DebouncePlrs[plr.Name] == nil then	
		
		DebouncePlrs[plr.Name] = true
		
		if Humanoid.MoveDirection.Magnitude > 0 and Humanoid.WalkSpeed > 0 then -- if moving
			
			local function Vault(target,ResultLow)
				
				if char["IsRunning?"].Value == true and char.Stamina.Value < (1000-StaminaRecoveryValue) and StaminaRecoveryDebounce[plr.Name] == nil then char.Stamina.Value += StaminaRecoveryValue; StaminaRecoveryDebounce[plr.Name] = true end

				print("Vaulting!!!!!!")
				local TargetPosition = (target.CFrame * CFrame.new(0, target.Size.Y / 2, 0) * CFrame.Angles(math.pi / 2, 0, 0) + Vector3.new(0,5,0))
				HRP.Anchored = true

				local Tween = TweenService:Create(HRP,TweenInfo.new(Humanoid.WalkSpeed / (1 + (460 * Humanoid.WalkSpeed / 26 ))),{["Position"] = ResultLow.Position + Vector3.new(0,target.Size.Y,0)})
				Tween:Play()
				Tween.Completed:Wait()
				
				local i = 0
				
				repeat
					local Tween2 = TweenService:Create(HRP,TweenInfo.new(Humanoid.WalkSpeed / (1 + (920 * Humanoid.WalkSpeed / 26))),{["Position"] = HRP.Position + HRP.CFrame.LookVector})

					
					
					local RaycastVaultDashThing = workspace:Raycast(HRP.Position,HRP.CFrame.LookVector*100,RayParams)	
					if RaycastVaultDashThing then
						if (RaycastVaultDashThing.Position - HRP.Position).Magnitude > 5 then
							Tween2:Play()
							Tween2.Completed:Wait()
						end
					else
						Tween2:Play()
						Tween2.Completed:Wait()
					end
					
					
					
					
					
					i += 1
				until i == 5
                
				HRP.Anchored = false
			local crtin = coroutine.create(function()
					task.wait(2)
					StaminaRecoveryDebounce[plr.Name] = nil
				end)
				
				coroutine.resume(crtin)
			end
			
			
			
			
			
			

			
			local ResultLowOffsetOrigin = 0.15 
			local ResultLowOffsetDirection = 0.15 
			
			
			local Result1 = workspace:Raycast(HRP.Position,HRP.CFrame.LookVector*100,RayParams) -- check if theres something in front the torso level of the character
			local ResultLow = workspace:Raycast(Vector3.new(HRP.Position.X,HRP.Position.Y - ResultLowOffsetOrigin,HRP.Position.Z),Vector3.new(HRP.CFrame.LookVector.X,HRP.CFrame.LookVector.Y - ResultLowOffsetDirection,HRP.CFrame.LookVector.Z)*100,RayParams) -- check if theres something infront of the leg level of the character
			
			-- Result1 is from HRP
			-- ResultLow is from around the leg level
			
			
			
			if ResultLow and ResultLow.Instance.Name ~= "Baseplate" then
				if Result1 then
					VisualizeRay(HRP.Position,Result1.Position,BrickColor.new("Yellow flip/flop"))
					VisualizeRay(Vector3.new(HRP.Position.X,HRP.Position.Y - ResultLowOffsetOrigin,HRP.Position.Z),ResultLow.Position,BrickColor.new("Baby blue"))
					
					print("Result1: " .. Result1.Instance.Name)
					print("ResultLow: " .. ResultLow.Instance.Name)
					
					if Result1.Instance ~= ResultLow.Instance and (HRP.Position - ResultLow.Instance.Position).Magnitude < MaxVaultDistanceFromPart then -- Checking if the part is not higher than character's legs 
						Vault(ResultLow.Instance,ResultLow)
					else
						Jump()
					end
					
					
				elseif (HRP.Position - ResultLow.Instance.Position).Magnitude < MaxVaultDistanceFromPart then
					
					print("ONLY ResultLow: " .. ResultLow.Instance.Name)
					VisualizeRay(Vector3.new(HRP.Position.X,HRP.Position.Y - ResultLowOffsetOrigin,HRP.Position.Z),ResultLow.Position,BrickColor.new("Baby blue"))
					Vault(ResultLow.Instance,ResultLow)
					
				end
			 
			
			
				
			else	
				
				Jump()
			end
			
			
		else	-- if not moving
			Jump()
		end
		
		
		




		DebouncePlrs[plr.Name] = nil
		

		

  end
end)

How can i make this script keep the serverside position and the client position the same?
Thanks in advance.

and also here:

You could send a remote event to the server AND THEN Tween to your desired positions. Honestly it’s kind of late so my brain isn’t as fresh right now. Hope it works though :slight_smile:

However, you’d have to do the rest of your calculations on the server.

Its already a serverscript,if i understood you correctly

1 Like

I mean you could check every second whether the Player’s position on the server is the same as on the client and set it to that (but this is extremely risky because any client can spoof the system).

You could use a sanity check to determine if the amount of studs the client has moved is reasonable. But honestly I’m too tired to do the math… sorry :frowning:

I can tell you’re testing right now (and the game isn’t public) so you could probably get away with this:

local rF = game.ReplicatedStorage.remoteFunction

task.spawn(function()
while task.wait(2.5) do
local cCFrame = rF:FireClient(serverCFrame)
-- cCFrame returns the Client’s CFrame
if cCFrame ~= serverCFrame then
plr.Character.HumanoidRootPart.CFrame = cCFrame
end
end
end)

I may be asleep by the time you respond. I’ve been responding to a lot of DevForum posts within the last few hours. Sorry in advance :frowning:

Sorry for not responding,why is the position even different? All the stuff is moving on the serverside

I’m not sure, never ran across this type of problem because well, I’ve never done anything related to this before. I don’t really have any suggestions but to well, maybe wait it out or test it in the actual game (like not in Studio).

I found the bug while i was trying to test the the actual game,so that wouldn’t work.
Does waiting out means wait for a bugfix?

Probably you would sadly. Since most of us aren’t regulars, we can’t really post but reports.

Tween the CFrame instead of position. If you select the model you will notice the bounding box is larger as the hrp is disconnected.

Do i need to tween the entire model CFrame or just the humanoidrootpart CFrame?

Models don’t have CFrames, you’d only be able to Tween the HumanoidRootPart’s CFrame (or other parts in your Character).

You should put the vaulting script on the client, as movement for your player is done on the client.

There is also something called “lag”, where the it takes time for the client to tell the server where you are, so on the server you are a few steps behind than on the client. This gets bigger with higher ping.

Wouldn’t it be really vulnerable to exploits?

Putting it on a remote event makes it more vulnerable.

It wouldn’t be any more vulnerable than it is already - exploiters could already make their own custom vaulting scripts if they wanted.

cc: @ZestyIsSour exploiters can already do whatever they want with their character.

Client calculates the character’s physics and because of this server has to wait client’s calculated position. You can get client’s position with InvokeClient or make vaulting script on the client.

That’s also very true. But putting it on a remote event just makes it even more vulnerable

Why though? Isn’t it good that the server is handling all the stuff and not the client?

Handling everything on the server worsens the ping for the server the player is on. And it can also cause memory leaks.

There’s no point trying to secure it that way, the best thing to do is to verify that the client moved the correct distance after vaulting, not to do the vaulting itself as that would be really laggy for the players with high ping.

Not in this case. Handling movement on the server without a whole lot of other complicated tricks on the client will just make moving around feel slow and choppy.

I was referring to a different reply, but it’s always good to inform those that don’t know anyway :hugs: