Simulating movement on given path on the server (no MonoBehaviour)

private void MoveToTarget(Action action = null)
        {
            ABPath path = CreatePath(_targetPosition);
            path.callback += (Path p) =>
            {
                _npc.CurrentServerPosition = p.vectorPath.Last();
                action?.Invoke();
                _isMoving = false;
            };


            _isMoving = true;
            AstarPath.StartPath(path);
        }

I’m using a Unity headless server. Currently I’m generating a path on the server and then sending the end position of said path to the client to handle the actual movement, which is all working fine. With my current set up though, there’s no way for the server to know the actual current position of the agent.

The above code works fine, but the problem is of course that the callback is called when the path is initially created. Would it be possible to simulate movement on the generated path on the server without having any instantiated agents? Then, I could just assume that the server and client positions are more or less in sync, given that they should be running the same path with the same parameters.

EDIT:
Ended up doing it like this, but I’m still wondering if there’s a better way to do it:

private void MoveToTarget(Action action = null)
        {
            ABPath path = CreatePath(_targetPosition);
            path.callback += (Path p) =>
            {
                _isMoving = true;
                Debug.Log("Path generated. Points: " + p.vectorPath.Count);

                foreach(Vector3 waypoint in p.vectorPath)
                {
                    while (_npc.CurrentServerPosition != (Vector2)waypoint)
                    {
                        _npc.CurrentServerPosition = Vector2.MoveTowards(_npc.CurrentServerPosition, waypoint, Time.deltaTime * _npc.MovementSpeed);
                    }
                    
                    Debug.Log("Waypoint reached.");
                    if (waypoint == p.vectorPath.Last())
                    {
                        Debug.Log("Path is complete.");
                        _isMoving = false;
                        action?.Invoke();
                    }
                    continue;
                    
                }
            };
            
            AstarPath.StartPath(path);
        }

Hi

That sounds like a pretty brittle solution. You seem to want movement done locally on the clients, but you still want pathfinding on the server? Normally I think either you have an authoritative server that simulates everything, or you let the clients calculate paths and send back the agent positions for whatever agents they own.

Indeed it is. I’m scanning the map on the client and using it both on the client and server. The server should generate the path (and also simulate the movement of the server agent on said path) and then send that path to clients to handle the visual part of the agents’ movement. Works well enough, but it’s of course important for the agent’s position/movement on the server to be simulated on the same path so that it stays in sync with the movement made on the client.

Since the the client and server are both working with the exact same data, do you think it would be feasible to just send the end position of the path to the client once it’s been generated, and then allow both the client and server to run their pathfinding independently? Does seem a bit brittle as well.

Server:

public async void FollowPlayer(Action callback = null)
        {
            if (_npc.PlayerInCombatWith == null)
                return;

            ABPath path = CreatePath(_npc.PlayerInCombatWith.Position);
            path.callback += async (Path p) =>
            {
                _isMoving = true;
                SendMovementPacket(p.vectorPath.Last()); // Send the target position to clients
                foreach (Vector3 waypoint in p.vectorPath)
                {
                    if (_npc.CurrentServerPosition == (Vector2)waypoint)
                        continue;
                    
                    while (_npc.CurrentServerPosition.SqrDistanceHigherThan(waypoint, 0.05f) && _npc.PlayerInCombatWith != null)
                    {
                        _npc.CurrentServerPosition = Vector2.MoveTowards(_npc.CurrentServerPosition, waypoint, _npc.MovementSpeed  * Time.deltaTime);
                        await new WaitForUpdate();
                    }
                }

                SendMovementPacket(_npc.CurrentServerPosition); // Make sure the client agent reaches the position of the server agent. This isn't ideal.
                _isMoving = false;
                callback?.Invoke();
            };

            AstarPath.StartPath(path);
        }

Client:

private void Update()
        {
            if (_aiDestinationSetter != null && _aiDestinationSetter.target != ServerPosition)
            {
                _aiDestinationSetter.target = ServerPosition;
            }
        }

ServerDestination being the position passed into “SendMovementPacket” on the server.

This is seemingly working fine, but like you said, it does come off pretty brittle, and I’m worried the client and server positions will eventually go out of sync.