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

NetworkRigidbody never syncs velocity, especially problematic for Distributed Authority #2903

Open Yoraiz0r opened 1 month ago

Yoraiz0r commented 1 month ago

Description

I witnessed bugged behavior when a rigidbody switches ownership in distributed authority, using the Transferrable flag without RequirePermission.

The symptom was such that once the object switched its authority from playerA to playerB, it would change how it moves.

This is because velocities (linear and angular) are not synced at all. I've confirmed as much in NGO 2.0.0-exp2's code. All NetworkRigidbody/NetworkRigidbodyBase does is manipulate the interpolation and kinematic state, and registers itself onto the network transform. The network transform has no awareness of the concept of neither linear nor angular velocities. It does not add any of them to its states.

Because of that, given even small amounts of lag, two objects can have wildly different opinions of how a non-kinematic rigidbody should be moving, and because of that, ownership cannot be easily transferred over.

Reproduce Steps

Though I have not used these exact steps, I have a simple project wherein I display the linear and angular velocities of a sphere being rolled by two players, the values show that despite the sphere rolling around when controlled by another player, its actual velocity values are zero'd out. See it here.

  1. Create a new project using NGO 2.0.0-exp2
  2. Create a scene with a NetworkManager and a way to host & join
  3. Add a sphere with a NetworkRigidbody, NetworkTransform, NetworkObject and set it to have Transferrable as true.
  4. Add a NetworkBehaviour that would set the rigidbody's linear velocity to a non-zero value (such as Vector3.Forward) on authority alone, on spawn.
  5. Add a button to allow claiming of ownership to another player.
  6. Begin a pair of player instances and make them join each other
  7. Witness the sphere moving for both players in a direction
  8. Let the joined player claim ownership of the sphere
  9. Witness that the sphere has stopped moving, because it has no linear velocity on its new owner.

Actual Outcome

Velocities are misaligned across clients, causing mismatch on ownership transfer.

Expected Outcome

Velocities are aligned and similar (identical) across all clients, allowing easy ownership transfer.

Screenshots

See the sample here, where

  1. The objects are colored based on their owner's client Id
  2. The top view shows editor gizmo overlays of linear velocity (top row), and angular velocity (bottom row), of the sphere.

The editor client represents the red player, Witness that while the sphere is blue, it has no/almost no linear velocity, despite moving.

Environment

Additional Context

I don't see any easy way to solve this one without editing the NetworkTransform class such that its synchronized state includes linear and angular velocities. I recognize this is far from an ideal solution, though.

There is no way to append new information to NetworkTransform state, nor is there any way to match its update rates, or interpolations.

At best, right now I'm experimenting with making a network behavior that uses network variables to store linear and angular velocities, and on ownership change, if you became the owner, apply those. I don't think this is the best nor right solution, and it lacks the whole 'unreliable deltas' etc based details that NetworkTransform supports.

Would love to know what's the proper way to go about solving this in the immediate, please!

Yoraiz0r commented 1 month ago

In attempt to further mitigate problems with ownership change in rigidbodies, I tried making ownership changes occur purely by distance to closest player. This clearly shows how the velocity is lost as soon as ownership is transferred.

https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/assets/1305336/740e9dff-66a4-4b3d-b916-e4ee69c749ef

The jitter is a result of the remaining linear and angular velocity on the client that originally pushed the object. They don't get cleared by the transfer.

Adding a NetworkBehaviour that synchronizes and applies linear and angular velocity helps mitigate the problem but ownership transfer is still subject to the lag that comes with the switch, arguably worse looking than on just touch.

https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/assets/1305336/54cada44-11ca-4830-9cee-c28a3fc95b9e

Given the position is rolling back, I believe this is more of a NetworkTransform issue than a Rigidbody issue, though.