How can I move my enemies smoothly throughout their path without comprising the security?

In Studio

In Game

How can I make them work smoothly like in studio but without sacrificing the security (manipulation with exploits)?

They all are created on server because it’s easier for me to implement logic to them and replicate to clients without doing anything plus its secure and it can’t be manipulated by exploiters. However ping and server lag/delay ruins the smoothness and when I try to put these on client it creates the problem of server not knowing where they are located and just their logic in general would be harder to implement.

How could I make them move smoother without making them look lagging? If I put them on client then what I do then? How can I can do that without comprising the security?

And also its worth noting that they are moved by 2 constraints called AlignPosition and AlignOrientation (each one of them).

I’m guessing the delay is there because of some discontinuity caused by the AlignPosition making the enemy reach the target position before it has the chance to update to the next one. Make sure the target position for each enemy is updated at a decent, fixed frequency and the AlignPosition has its parameters properly tuned.

If I were to approach this problem, though, I would scrap the constraints, have the server inform the clients of each enemy’s physics state at a fixed frequency, and then interpolate on the client.

I could try to do that, though without constraints it would be difficult.

Wait the distance / walkspeed - 0.05 before moving onto the next point. This will wait until the heartbeat when the NPC stops, or the heartbeat before. Then you can navigate to the next waypoint.

Maybe changes in network ownership is causing the problem?? You could try setting the network owner of each enemy’s root part to the server.

local function onEnemyCreated(enemy: Model)
    -- model has to be parented to workspace
    -- before setting network owner
    enemy.Parent = workspace
    local root = enemy:FindFirstChild("HumanoidRootPart")
    root:SetNetworkOwner()
end
Network Ownership API cannot be called on Anchored parts or parts welded to Anchored parts.

I am pretty sure its already on a server due to this occurring when I try to set it.

I don’t see any difference if I have that or not.

Helper:Wait((MoveNode.WorldPosition - targetNode.WorldPosition).Magnitude / Model:GetAttribute("WalkSpeed"))

You must subtract 0.05. That is the KEY difference. If you don’t see an effect, subtract more to test if it is actually working.

If you’re just moving your enemies with Humanoid:MoveTo, you would have to unanchor the parts first before it starts moving (unless they’re being unanchored and moved on the client).

You should try setting network ownership immediately after unanchoring.

Can you elaborate more on this? Is it necessary to unanchor the enemy?

It’s necessary to unanchor the enemy in order to use :SetNetworkOwner.

So this is what I think is happening:

  1. The server tells the humanoid to move to a new position using Humanoid:MoveTo.

  2. Because the humanoid is being network owned by a nearby player (due to auto network ownership), the :MoveTo message has to travel to that player’s client-side first, which takes some time based on ping.

  3. Once the humanoid is finished moving, the client fires the .MoveToFinished event.

  4. Again, because the humanoid is network owned by a nearby player, the .MoveToFinished message has to travel back to the server, which also takes some time based on ping.

  5. The server receives the event signal, go back to step 1.

Here’s an example place showing what I mean: HumanoidNetworking.rbxl (34.2 KB)

You can change the SetNetworkOwner attribute on Workspace.Dummy.Script to see the difference when you do and don’t set the network owner.

Changes in the humanoid’s network ownership will be clear as day if you set Incoming Replication Lag to something like 0.05 in your Studio settings.

No :SetNetworkOwner
NoSetNetworkOwner

With :SetNetworkOwner
WithSetNetworkOwner

Anyway, setting the network owner to the server eliminates steps 2 and 4, because the server will be in control of firing the .MoveToFinished event and handling the :MoveTo call.

You wouldn’t be able to notice this in Studio because your ping would typically be nearly instant without changing Incoming Replication Lag. In-game, ping can change wildly based on which server you connect to.

3 Likes