Laggy Pathfinding

I was always wondering how people could make pathfinding not choppy. I have attempted to make Pathfinding to be super smooth by doing all the computing on the client and sending the waypoints to server to move the humanoid but it ended up still being choppy. I would like to have someone review to my code and improve or give advice on it. Thanks : )

WHATS WRONG VVVV
https://gyazo.com/4571575e0383753710c1b35ec7bd2df7

Client Code:

--Functions
local function GetWaypoints(StartPos, EndPos)
	local Path = PFS:CreatePath();
	Path:ComputeAsync(StartPos, EndPos)

	return Path:GetWaypoints()
end

local function GetDistance(Part1, Part2)
	local Pos1 = Part1.CFrame.Position;
	local Pos2 = Part2.CFrame.Position;

	return math.sqrt((Pos1.X - Pos2.X)^2 + (Pos1.Y - Pos2.Y)^2 + (Pos1.Z - Pos2.Z)^2);
end

local function CreatePathfindingThread(Troop)
	spawn(function()
		local Allowed = true
		local Hum = Troop:FindFirstChildOfClass("Humanoid");
		local HumRoot = Troop:WaitForChild("HumanoidRootPart");
		local PlrChar = plr.Character or plr.CharacterAdded:Wait();

		local Waypoints = GetWaypoints(HumRoot.CFrame.Position, PlrChar.HumanoidRootPart.CFrame.Position);
		
		game.ReplicatedStorage.Events.TroopReplicate.OnClientEvent:Connect(function(PassedHum)
			if (Hum == PassedHum) then
				Allowed = true;
			end
		end)

		while Hum and Hum.Health > 0 do
			if (GetDistance(PlrChar.HumanoidRootPart, HumRoot) > 15 and Allowed) then
				game.ReplicatedStorage.Events.TroopReplicate:FireServer(Hum, Waypoints, 3);
				Allowed = false;
			end
			spawn(function()
				Waypoints = GetWaypoints(HumRoot.CFrame.Position, PlrChar.HumanoidRootPart.CFrame.Position); 
			end)
			wait()
		end
	end) 
end

Server:

Events.TroopReplicate.OnServerEvent:Connect(function(plr, Humanoid, Waypoints, Amount)
	for i = 3, Amount-1 do
		if (Waypoints[i]) then 
			Humanoid:MoveTo(Waypoints[i].Position);
			if (Waypoints[i].Action == Enum.PathWaypointAction.Jump) then
				Humanoid.Jump = true;
			end
			Humanoid.MoveToFinished:Wait();
		end
	end
	Events.TroopReplicate:FireClient(plr, Humanoid)
end)

Any help will be great : )

3 Likes

Instead of simply running in a while loop for health, try attaching it to the render step.

This makes it run every time the client re-rerenders. You can still have the logic to do with health, simply use an if statement instead.

This should make it slightly smoother.

1 Like

Hmm good point, ill try that in a second

Nope it hasn’t made a difference

The problem is that you are telling the NPC to start walking a new path roughly 30 times a second (the length of a wait()). Not only can pathfinding this many times, over large distances, with multiple NPCs slow down a game, but your server is spawning multiple Lua threads (coroutines, not actual threads) to handle these events, each interrupting the last and telling the Humanoid to restart walking the path.

I’d recommend having a single thread on the server to walk the waypoints. When the server receives a request to update the waypoints, the newly spawned thread updates the waypoints and quickly exits. The single thread handling the waypoints should continue to walk to the previous waypoint it was going to and continue to walk the waypoints which may have been updated while it was sleeping. The client should be made aware when the NPC reaches a waypoint through a remote event so that it knows the next point the NPC will stop and switch paths and can calculate any new paths starting from there.

A little more work but for a nicer effect would be to allow the client to interrupt a NPC’s current path. This would require waking up the thread that is walking the waypoints before it reaches the next waypoint. I’d use a CustomEvent for this which is fired when a waypoint is reached or the client wants to interrupt the path. This interrupt should be done very rarely to avoid running into the issue that you are seeing (maximum of once every second / when a drastic path change as occurred).

12 Likes

Ill try this once I hear the other persons response : ), thanks for your time!

The reason why this is happening is because of lag between the client and the server.

  1. Server sends instructions to the humanoid to move to some waypoint. The server doesn’t actually move the humanoid because it’s network owned by the client.

  2. Instead, the client receives this instruction, and replicates to the humanoid, which takes a little lag

  3. Humanoid is done moving to the waypoint from the client, but not on the server because of replication lag. This is what causes the humanoid to stop every couple moments.

  4. Server finally receives the replicated response from the client when the humanoid is done moving, and sends another command to the humanoid to move to the next waypoint, which brings us back to step 1.

By setting network ownership to the server, this is what happens:

  1. Server sends instructions to the humanoid, and the humanoid acts immediately.

  2. Once the humanoid reaches the point, server instantly gets the signal that the humanoid stopped, and moves on to the next waypoint.

I recommend you try this after you get your events working (aka using the suggestion above), because it is sure to pop up in every situation involving pathfinding.

Also, if you want to make this all work from the server, it might just be better to get the server to find the humanoid root part’s position and update from there, as you will get the same results, trust me.

2 Likes

Thanks for everyone for the response, I see what I did wrong and ill act quick to fix. Much thanks to all of you <33333

5 Likes