NaveMesh considerations for server authoritative setup?

Context:

In my RTS prototype, I am doing my best to ensure that I keep as much state as possible server authoritative using a Simulator, but I am running into some lag/performance issues, which I suspect could be related to shoehorning in state bindings where I could. This is making me re-think how my entities are set up, and I am starting with the movement mechanics used by the individual RTS units.

What I’ve tried:

Currently, I have a navmesh on the map paired with navmeshagents on the individual units. When the client wants to “move” a unit, it sends a command to the sync which when received on the simulator, updates the destination property for the agent, causing the agent to move on the simulator. I paired this with a naive approach to bind the unit’s position and rotation properties as replicated fields. This worked initially for seeing a unit move but fell short with missing walk/run animations. Before adding Coherence, I used a component on my unit to observe the velocity of the navmesh agent and update a float value on my animation controller on each Update(). This then controlled a blend between idle, walk, & run.

To overcome the velocity no longer being present on the local navmeshagent, I next tried adding the velocity property to be a bound replicated value. This solved my problem, and the animation controller now correctly moves through its blended states, but I question if this was the best approach.

The question:

How is Coherence commonly paired with entities using navmeshagents & an authoritative Simulator?

I could see a few approaches:

  • Only run the navmesh & agent on the simulator, and replicate all resulting values (position, rotation, etc.)
  • Run the navmesh & agent on the client and simulator, and keep the “destination” property of the agent sync’d

I believe the second approach would work better, but I question if updating the agent’s destination is “valid” if the intent is for full server authority.

1 Like

Interesting question! As you might have understood by now, coherence is not prescriptive in any specific way of doing things.

So what could be more logical…? In my personal opinion, the first way. You said it yourself: if the priority is have a server-authoritative simulation, then for me it makes more sense to sync the position of all units. If you sync only the destination and then let each client calculate the path, you might incur in a situation where, because of another unit synced with different timing on different clients, the original character takes different paths on different machines, with catastrophic effects (including that they would arrive at vastly different times). So for me, position and rotation it is! :+1:t2:

And then yes, you could sync the velocity too. That’s the easiest. Or let each client calculate it based on the difference of position between frames? That would make the most sense for two reasons, in my opinion:

  • First, less network data
  • Second, by doing this the parameter would be strictly tied to the actual velocity at the moment, resulting in a more precise animation. If you rely on a synced value, you might get a slight mismatch due to network lag, with animations not reacting immediately based on what the unit is doing. Maybe!
1 Like

Thanks for the reply @ciro. I took your advice and moved forward with syncing just the transform properties, and so far, it is working well.

Also, I found the root cause for the lag which made me initially start looking into this in the first place; it was due to GC Alloc’s happening on the simulator from a component that didn’t need to be run when headless. Funny enough your Unity profiler video was what helped me figure it out lol.

2 Likes

Nice!

That video keeps popping up, it was good value considered how bad I am myself at profiling :rofl:

1 Like