Why is there so much latency here and how do I deal with it?

I have a LocalScript to allow players to sprint that gets player input and has to fire some RemoteEvents and RemoteFunctions to change the walking speed and do server-sided checks.

--LocalScript.

local running = false

mouse.KeyDown:Connect(function(key)

	if string.byte(string.lower(key)) == 48 then
		local CheckLoaded = game.ReplicatedStorage:WaitForChild("RemoteFunctions"):WaitForChild("RF1"):InvokeServer(1)
		local CheckLegBroken1 = game.ReplicatedStorage:WaitForChild("RemoteFunctions"):WaitForChild("RF1"):InvokeServer(2)

		if CheckLoaded == true and CheckLegBroken1 == false then
			running = true

			local KeyConnection = mouse.KeyUp:Connect(function(key)
				if string.byte(key) == 48 then running = false end
			end)

			game.ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("RE2"):FireServer(3)

			repeat
				local CheckLegBroken2 = game.ReplicatedStorage:WaitForChild("RemoteFunctions"):WaitForChild("RF1"):InvokeServer(2)
				wait()
			until running == false or CheckLegBroken2 == true

			KeyConnection:Disconnect()
			game.ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("RE2"):FireServer(2)
		end

	end

end)



--Script.

RE2.OnServerEvent:Connect(function(player, request)

	if player:FindFirstChild("Data"):FindFirstChild("LegBroken") then

		if player.Data.LegBroken.Value == true then
			player.Character:WaitForChild("Humanoid").WalkSpeed = 6

		elseif player.Data.LegBroken.Value == false and request == 2 then

			player.Character:WaitForChild("Humanoid").WalkSpeed = 10

		elseif player.Data.LegBroken.Value == false and request == 3 then

			player.Character:WaitForChild("Humanoid").WalkSpeed = 14
		end

	end

end)

RF1.OnServerInvoke = function(player, request)

	if request == 1 then
		return player:WaitForChild("Data"):WaitForChild("Loaded").Value

	elseif request == 2 then

		return player:WaitForChild("Data"):WaitForChild("LegBroken").Value

	elseif request == 3 then

		return game.ServerStorage.ServerVersion.Value
	end

end

I’m guessing it’s because of the RemoteFunctions and they would have to yield the thread until they get a return value. But is there maybe anything else that’s causing so much latency? When I press SHIFT, it takes almost more than a second to change the walking speed. I’m quite sure it’s not the RemoteEvents because I did not use RemoteFunctions to check on the server before and there wasn’t really any latency. Sorry if I’m not providing enough information but I’m on a phone right now and will improve when I get the chance.

I think that you should update the speed on the client side as well. You should always do this for immediate feedback. Plus the effects will still be replicated. There will always be that latency with remotes.

The internet is not instant so it will take time to send things to the other side of the network. In addition, if the latency is real bad you can probably make an animation to “hide” it.

And as a side note do not use KeyDown; it is deprecated. instead use user input service or context action service: https://developer.roblox.com/api-reference/class/UserInputService / https://developer.roblox.com/api-reference/class/ContextActionService

Edit: just read the remote function server code and why does the player need to request information they have access to? The data is under their player instance?

1 Like

You should store state that you need to check for client-side, and the server should replicate changes to it when they occur. The client shouldn’t need to request values every time.

1 Like

The thing is I want to check on the server because hackers could probably change some things on the client.

They can always change their client-side values, the key is not to rely upon them and do server-side checks anyway. You can still make these checks.

Okay, but you can check on both the server and client. The client doesn’t need to request information they already have access to anyways. Currently you’re doing it only on the server. There isn’t that immediate feedback. And the WalkSpeed can easily be exploited already so you might as well just do that client sided too as I said.

Change walkSpeed on the client, but make sure if you have any anti-walkSpeed exploits that they won’t ban the person. This typically won’t happen, if you check for the speed being higher. However, you might want to fire the server the value if you want the server to have anti-cheats.

Basically:

  • Client changes walkspeed
  • Client fires server to tell the server the new walkSpeed
  • Server updates value on the server side to prevent exploits (if you want to incorperate them to prevent users from hacking to go normal speed while crouching)
  • Server checks using updated value for anti-cheat purposes

Be me, exploiter.

local yourRemote = path_to_update_remote
local myCharacter = game:GetService("Players").LocalPlayer.Character
local myHumanoid = myCharacter:FindFirstChildOfClass("Humanoid") -- Not taking chances
local myWantedSpeed = 500

if myHumanoid then
    myHumanoid.WalkSpeed = 500
    yourRemote:FireServer(500 + 50) -- Heehee! Can't get me if I'm not moving quicker than expected!
end

Moral of the story: this isn’t going to work. Your security model is client-authoritative and the server is relying on the client to tell it what value it should accept. That’s a big no-no.

The client and server should be handling WalkSpeed updates or caching in their own respective mannerism. The client updates their own WalkSpeed so there is no delay between input and the server does so in order to have a basis for comparison or to determine if a character’s physics are updating faster than they should be.

2 Likes