diff --git a/com.unity.netcode.gameobjects/Documentation~/ghostobjects.md b/com.unity.netcode.gameobjects/Documentation~/ghostobjects.md index 333d3e6f8d..fa9fe14402 100644 --- a/com.unity.netcode.gameobjects/Documentation~/ghostobjects.md +++ b/com.unity.netcode.gameobjects/Documentation~/ghostobjects.md @@ -86,6 +86,13 @@ To convert a hybrid object back into a prefab that uses only one package, remove > [!NOTE] > Unity might prevent you from removing a **GhostObject** or **NetworkObject** component while the GameObject has `GhostBehaviour` or `NetworkBehaviour` components that depend on it. Remove the dependent components first. +## Mixed mode objects and physics + +To avoid visual anomalies, NGO automatically adjusts some Rigidbody settings based on the **Physics Run Mode** of the `NetcodeConfig` asset: + +- **Always Run**: In a session that has hybrid prefabs, non-hybrid NGO prefabs with a NetworkRigidbody and a 3D Rigidbody have the Rigidbody's **Interpolate** value set to **Extrapolate** on the authority instance and to **None** on all non-authority instances. The authority instance is the server or host for a server-authoritative NetworkTransform, or the owner for an owner-authoritative one. The value follows authority when ownership changes, and the original value is restored when the instance despawns. +- **User Controlled**: Hybrid NGO prefabs with a NetworkRigidbody have **Full Tick Smoothing** set to **Disabled**. + ## Additional resources - [GhostObjects in Unity Netcode](https://docs.unity3d.com/Packages/com.unity.netcode@latest?subfolder=/manual/ghostobject/ghostobject.html) diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs index d55b2f30e8..cbc4b3a5ad 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs @@ -298,6 +298,25 @@ private bool InitializeHybrid() return true; } + // Overrides the authored interpolation while spawned when the NetcodeConfig physics mode requires it. + private bool m_UsePhysicsModeInterpolation; + + /// + /// Prevents the jitter an interpolated Rigidbody that is not a GhostObject shows in a hybrid session with . + /// + private void SetPhysicsModeInterpolation() + { + var netcodeConfig = NetcodeConfig.Global; + m_UsePhysicsModeInterpolation = !m_IsRigidbody2D && m_LocalNetworkManager.NetworkConfig.Prefabs.HasGhostPrefabs + && netcodeConfig != null && netcodeConfig.PhysicsRunMode == PhysicGroupRunMode.AlwaysRun; + } + + // The authority extrapolates and every other peer does not interpolate. + private void ApplyPhysicsModeInterpolation() + { + SetInterpolation(m_IsAuthority ? InterpolationTypes.Extrapolate : InterpolationTypes.None); + } + /// /// Kinematic on every peer except the server. Called at spawn because an in-scene placed instance has no session during Awake. /// @@ -956,6 +975,14 @@ private void PostSetIsKinematic() return; } +#if UNIFIED_NETCODE + if (m_UsePhysicsModeInterpolation) + { + ApplyPhysicsModeInterpolation(); + return; + } +#endif + if (UseRigidBodyForMotion) { // Exit early if the original interpolation type is not set to extrapolate or NetworkTransform interpolate is disabled @@ -1103,6 +1130,12 @@ internal void UpdateOwnershipAuthority() { SetIsKinematic(!m_IsAuthority); } +#if UNIFIED_NETCODE + else if (m_UsePhysicsModeInterpolation) + { + ApplyPhysicsModeInterpolation(); + } +#endif } internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManager) @@ -1122,6 +1155,9 @@ public override void OnNetworkSpawn() #endif m_TickFrequency = 1.0f / m_LocalNetworkManager.NetworkConfig.TickRate; m_TickRate = m_LocalNetworkManager.NetworkConfig.TickRate; +#if UNIFIED_NETCODE + SetPhysicsModeInterpolation(); +#endif UpdateOwnershipAuthority(); } diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs index 68725f3bbd..3a03a59bd8 100644 --- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs @@ -179,6 +179,18 @@ public bool Validate(int index = -1) #if UNIFIED_NETCODE // Mark this network prefab as having to be registered via the unified API HasGhost = networkObject.HasGhost; + +#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D + // With UserControlled physics, full tick smoothing holds a hybrid Rigidbody in place on the host. + var netcodeConfig = NetcodeConfig.Global; + if (HasGhost && netcodeConfig != null && netcodeConfig.PhysicsRunMode == PhysicGroupRunMode.UserControlled + && networkObject.GhostObject.FullTickSmoothing != FullTickSmoothingMode.Disabled + && networkObject.GetComponent() != null) + { + NetworkLog.LogWarning(new Logging.Context(LogLevel.Developer, $"Disabling full tick smoothing on {networkObject.name} because the {nameof(NetcodeConfig)} physics mode is {PhysicGroupRunMode.UserControlled}.").AddNetworkObject(networkObject)); + networkObject.GhostObject.FullTickSmoothing = FullTickSmoothingMode.Disabled; + } +#endif #endif if (networkObject.InScenePlaced) {