com.unity.netcode.gameobjects icon indicating copy to clipboard operation
com.unity.netcode.gameobjects copied to clipboard

ClientNetworkTransform interpolation on changing ownership

Open rever96 opened this issue 1 year ago • 6 comments

The problem: Change ownership of physic gameobject makes it goes back and forth on its path.

https://user-images.githubusercontent.com/19595534/208450265-13ba370e-971e-40d6-a28f-ae9c02283256.mp4

the client that lose the ownership see this bug I think because when he lose the ownership the other client become authoritative and send him the old position value

Request: I would like that changing ownership would work out of the box

Describe alternatives you've considered I tried syncing position and velocity throught networkvariable, OnLostOwnership and OnGainedOwnership callbacks, rpcs without good results

Current Implementation:

image

current logic NetPhysicBall:


    private void Update()
    {
        if (IsOwner && !_isChangingOwnership)
        {
            float distanceToLocal = Vector3.Distance(transform.position, localTransform.position);
            float distanceToEnemy = Vector3.Distance(transform.position, enemyTransform.position) + 2f;
            // se la palla è dall'altra parte del campo di questo client
            if (distanceToEnemy < distanceToLocal)
            {
                Debug.Log(
                    $"NetPhysicBall::Change Ownership: {gameObject.name} => {(IsServer ? 1 : 0)}, currentPos={transform.position}, currentVelocity={rb.velocity}");
                _isChangingOwnership = true;

                ChangeOwnershipServerRpc(rb.position, rb.velocity);
            }
        }
    }

    [ServerRpc]
    private void ChangeOwnershipServerRpc(Vector3 pos, Vector3 vel)
    {
        ChangeOwnershipClientRpc(pos, vel);
    }


    [ClientRpc]
    private void ChangeOwnershipClientRpc(Vector3 pos, Vector3 vel)
    {
        Debug.Log(
            $"NetPhysicBall::ChangeOwnershipClientRpc: {gameObject.name} {!IsOwner}, pos={pos}, realPos={rb.position}, vel={vel}, realVel={rb.velocity}");

        _velocity = vel;
        _position = pos;
        
        Debug.DrawLine(pos, pos + vel * 0.2f, Color.yellow, 2f, false);
        Debug.DrawLine(pos, pos + vel * 0.1f, Color.red, 2f, false);
        // se sono il server aggiungo logica di cambio ownership
        if (IsServer)
        {
            // se sono il server, ma non l'owner imposto il prossimo owner con il mio Id
            ulong clientId = IsOwner
                ? ((MultiGameManager)(ServerGameManager.Instance)).enemyClientId
                : NetworkManager.LocalClientId;

            Debug.Log($"Server NetPhysicBall::ChangeOwnershipClientRpc: {gameObject.name} => {clientId}");
            NetworkObject.ChangeOwnership(clientId);
        }
    }

    public override void OnLostOwnership()
    {
        Debug.Log($"NetPhysicBall::OnLostOwnership: {gameObject.name}");
        _isChangingOwnership = false;
    }

    public override void OnGainedOwnership()
    {
        if (!IsOwner)
        {
            // devo uscire perchè l'host riceve questa callback anche quando non è lui il nuovo owner
            return;
        }

        Debug.Log($"NetPhysicBall::OnGainedOwnership: {gameObject.name}");
        
        rb.velocity = _velocity;
    }

rever96 avatar Dec 19 '22 14:12 rever96

@rever96 Hello, I am looking at this issue and believe it has been fixed. If you wouldn't mind, could you use a development branch where I have made quite a few improvements to verify it is fixed? If so, the easiest way to do this is:

  • make a back up of your Packages\manifest.json file
  • replace your (com.unity.netcode.gameobjects) with the following: "com.unity.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#refactor/quaternion-synchronization-network-transform"
  • once done verifying whether it does (or does not) resolve your issue, you can replace the modified manifest.json file with your backed up one.

If you are able to do this, then could you let me know if this branch resolves your issue?

If not, then I will look further into the issue and see if I can get a test to replicate it on my end (or if you have a repository link that replicates the issue that would be faster).

NoelStephensUnity avatar Jan 11 '23 00:01 NoelStephensUnity

I'll check with your branch soon as possible. thanks,

For now I made an implementation thats delay the gameplay: mspaint_BHrby5gEoM

the client that have the ownerhip when it change disable the networktransform to freeze the position (in scheme pos 3) until the new owner reach the position making it smooth on the client that receive the ownership, but makes a freeze on other client. Here is the described implementation (nasty but working code) NetPhysicBall.zip

rever96 avatar Jan 12 '23 13:01 rever96

@rever96 Thank you for including this zip. I will look at your implementation and see if I can replicate the issue on my side. From the sound of it, you have a period of time when the ball is transferring ownership and during this time there is the latency between clients and the relative ball position that is causing interpolation issues.

A "quick" way to handle this would be to disable interpolation while ownership is changing and to provide a predicted position based on the owner's latency to the server by using NetworkManager.NetworkConfig.NetworkTransport.GetCurrentRtt(). Once ownership is transferred then you can re-enable it. Alternately, you could try teleporting to the predicted position, but I still think you will have a small "stutter" visually using that approach too.

However, I think there could be an alternate way to approach this type of motion model scenario that could be less problematic.

(To help me with coming up with a solution for you, it would help to know a few things about your project first:) Are you running a server (i.e. not a host) that has two clients connected? If so, then are you making the NetPhysicBall change ownership to get around input latency? I am asking this because (without seeing the project as a whole) it appears there could be a different way to approach this type of motion model without having to change ownership. I need to know whether you have a server and two clients or a host with a connected client before I provide more details about the alternate approach.

NoelStephensUnity avatar Jan 12 '23 15:01 NoelStephensUnity

My use case is Host vs Client without a Server. only 2 players. I checked the branch that you suggested before, but it doesn't help, the improvements that you made here are all about rotations that has no bearing on my problem. And yes, using a predicted position will result in a teleport of the ball on the client that receive the ownership (in the schema the red "pos 4" represent this possibility and it's worst than the freeze solution I applied)

rever96 avatar Jan 12 '23 17:01 rever96

@rever96 I understand. This is an issue that is deeper than change in ownership as it involves the change in ownership and synchronizing the transform during the change in ownership.

Let me see if I can work up an example that basically handles blending between user inputs over time.
The general idea is for the ball to have an existing applied force that decays over time and depending upon who the owner is depends upon how much "pending force" is applied (which would include direction) by the user. As opposed to directly applying the force based on the user's input, it would track player's input. Most likely non-owner client input would be updated by an RPC since RPCs are sent immediately as opposed to NetworkVariables that are synchronized every network tick (i.e. if the default network tick is 30 then every 33ms). Depending upon who the owner is would depend upon who is sending the RPC and the owner would always update their value locally as well as send an RPC. The ball's "current applied force" (a value synchronized by both sides) is what would be used by the current owner when adding force to the RigidBody.

As a side note, the issue your are experiencing has more to do with client-side prediction and interpolation in combination with the change in ownership so it might be that it requires de-coupling the visual components from the NetworkObject itself and handling the lerping between the "gap" while ownership changes.

This could take until early next week before I have an example you could look at as reference point.

NoelStephensUnity avatar Jan 13 '23 00:01 NoelStephensUnity

Hi, I'm having this exact issue in 1.8.1. Is there a fix for this yet?

StaleC00kie avatar Feb 27 '24 02:02 StaleC00kie