Unity-Technologies / com.unity.netcode.gameobjects

Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.
MIT License
2.1k stars 430 forks source link

Client/Owner authoritative NetworkTransform and Re-Parenting issue #2842

Open zachstronaut opened 3 months ago

zachstronaut commented 3 months ago

When you have a moving client/owner authoritative NetworkTransform and the server changes its parent, the position where that object was on the server at the moment of the re-parenting gets serialized back to the client. The client is pushed back to a previous position (essentially back in time).

This problem isn't happening inside of NetworkTransform, though. You can observe the same issue where the client jumps to the server's position upon re-parenting if you have no NT at all.

The source of this problem is actually in ParentSyncMessage.Handle() messing with the position of objects and not respecting that somebody other than the server may own the position of the object.

NoelStephensUnity commented 3 months ago

I see where the issue could arise with an owner authoritative instance. I could add a NetworkObject.AutoParentingTransformSync property that would default to true (to not break the existing behavior), but if that was disabled then it would not apply any transform values when parenting occurred... but your issue is really specific to the owner/client authoritative motion model.

Of course, we are getting much closer to releasing the alpha package for distributed authority that provides full client-side authority over owned NetworkObjects... so at that point you can just parent the NetworkObject on the client-side where transform values will synchronize to the client owner's values (which would completely resolve your issue).

I am restricted from providing details on when this will be available, but I can say to keep watching the repository as it will get a relatively large update soon (i.e. in a few weeks). While the update won't be specific to the develop branch it will have some new branches that will have some rather large changes.

Let me weigh the benefits of adding that property vs holding back until the distributed authority is available (i.e. landed in the repo not the official package).

(Have several ideas of how you could work around this issue...but again... distributed authority update will resolve these kinds of issues "by design"...so I am hesitant sending you in a direction that you will most likely replace once DA is available).

zachstronaut commented 3 months ago

@NoelStephensUnity Thanks! I'm pretty sure I can make customizations to Netcode myself locally to fix this one, but I wanted to make sure it was on the radar as a problem with client authority.

However, I haven't been able to figure out my own solution to this other kinda related problem yet:

https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues/2843

I've been able to reduce the problem down to what I assume is a single tick of bad positioning, but that's still a huge visual glitch.

zachstronaut commented 3 months ago

@NoelStephensUnity It seems like a small change to ParentSyncMessage.cs fixes this issue with owner/client authoritative position snapping back in time:

public void Handle(ref NetworkContext context)
{
    var networkManager = (NetworkManager)context.SystemOwner;
    var networkObject = networkManager.SpawnManager.SpawnedObjects[NetworkObjectId];
    networkObject.SetNetworkParenting(LatestParent, WorldPositionStays);
    networkObject.ApplyNetworkParenting(RemoveParent);

    // We set all of the transform values after parenting as they are
    // the values of the server-side post-parenting transform values
    if (!WorldPositionStays)
    {
        networkObject.transform.localPosition = Position;
        networkObject.transform.localRotation = Rotation;
    }
    // THE FIX
    // else
    // {
    //     networkObject.transform.position = Position;
    //     networkObject.transform.rotation = Rotation;
    // }
    networkObject.transform.localScale = Scale;
}

This makes me wonder in what circumstances you would even need to be writing position/rotation information when re-parenting is WorldPositionStays since by definition the position hasn't changed from the re-parenting?

NoelStephensUnity commented 2 months ago

If changes are made on the authority side to the transform upon a NetworkObject being parented (i.e. within OnNetworkObjectParentChanged) and there is no NetworkTransform then this scenario applies. There have been on-going issues with handling parenting under various scenarios (especially if a NetworkTransform is attached to the GameObject in question).

Side Note: With NGO v2.0.0 we will be migrating all of the components assembly into the runtime assembly which will make the above conundrum much easier to determine if it should apply changes or let NetworkTransform handle the changes when parenting.