diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index d618645fdc..1a0766b5f1 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Added +- Added tooltips for all of the `NetworkObject` component's properties. (#3052) - Added message size validation to named and unnamed message sending functions for better error messages. (#3049) - Added "Check for NetworkObject Component" property to the Multiplayer->Netcode for GameObjects project settings. When disabled, this will bypass the in-editor `NetworkObject` check on `NetworkBehaviour` components. (#3031) - Added `NetworkTransform.SwitchTransformSpaceWhenParented` property that, when enabled, will handle the world to local, local to world, and local to local transform space transitions when interpolation is enabled. (#3013) @@ -20,6 +21,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed issue where an exception could occur when receiving a universal RPC for a `NetworkObject` that has been despawned. (#3052) - Fixed issue where a NetworkObject hidden from a client that is then promoted to be session owner was not being synchronized with newly joining clients.(#3051) - Fixed issue where clients could have a wrong time delta on `NetworkVariableBase` which could prevent from sending delta state updates. (#3045) - Fixed issue where setting a prefab hash value during connection approval but not having a player prefab assigned could cause an exception when spawning a player. (#3042) @@ -30,6 +32,9 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed +- Changed `NetworkTransformEditor` now uses `NetworkTransform` as the base type class to assure it doesn't display a foldout group when using the base `NetworkTransform` component class. (#3052) +- Changed `NetworkAnimator.Awake` is now a protected virtual method. (#3052) +- Changed when invoking `NetworkManager.ConnectionManager.DisconnectClient` during a distributed authority session a more appropriate message is logged. (#3052) - Changed `NetworkTransformEditor` so it now derives from `NetcodeEditorBase`. (#3013) - Changed `NetworkRigidbodyBaseEditor` so it now derives from `NetcodeEditorBase`. (#3013) - Changed `NetworkManagerEditor` so it now derives from `NetcodeEditorBase`. (#3013) diff --git a/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs index 7d8b26522c..e93226e2bd 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs @@ -9,7 +9,7 @@ namespace Unity.Netcode.Editor /// [CustomEditor(typeof(NetworkTransform), true)] [CanEditMultipleObjects] - public class NetworkTransformEditor : NetcodeEditorBase + public class NetworkTransformEditor : NetcodeEditorBase { private SerializedProperty m_SwitchTransformSpaceWhenParented; private SerializedProperty m_TickSyncChildren; diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs index e01f4e7795..ca3218a1a2 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkAnimator.cs @@ -584,7 +584,7 @@ public override void OnDestroy() base.OnDestroy(); } - private void Awake() + protected virtual void Awake() { int layers = m_Animator.layerCount; // Initializing the below arrays for everyone handles an issue diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs index 13fb21a5ce..b9d8eabab3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs @@ -3604,8 +3604,12 @@ private void SetStateServerRpc(Vector3 pos, Quaternion rot, Vector3 scale, bool } /// - /// Teleport the transform to the given values without interpolating + /// Teleport an already spawned object to the given values without interpolating. /// + /// + /// This is intended to be used on already spawned objects, for setting the position of a dynamically spawned object just apply the transform values prior to spawning.
+ /// With player objects, override the method and have the authority make adjustments to the transform prior to invoking base.OnNetworkSpawn. + ///
/// new position to move to. /// new rotation to rotate to. /// new scale to scale to. diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index af97de8d06..b5fff5404d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -1299,7 +1299,15 @@ internal void DisconnectClient(ulong clientId, string reason = null) { if (!LocalClient.IsServer) { - throw new NotServerException($"Only server can disconnect remote clients. Please use `{nameof(Shutdown)}()` instead."); + if (NetworkManager.NetworkConfig.NetworkTopology == NetworkTopologyTypes.ClientServer) + { + throw new NotServerException($"Only server can disconnect remote clients. Please use `{nameof(Shutdown)}()` instead."); + } + else + { + Debug.LogWarning($"Currently, clients cannot disconnect other clients from a distributed authority session. Please use `{nameof(Shutdown)}()` instead."); + return; + } } if (clientId == NetworkManager.ServerClientId) diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 591fd417e7..f89bc1d345 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -938,6 +938,7 @@ private bool InternalHasAuthority() /// /// If true, the object will always be replicated as root on clients and the parent will be ignored. /// + [Tooltip("If enabled (default disabled), instances of this NetworkObject will ignore any parent(s) it might have and replicate on clients as the root being its parent.")] public bool AlwaysReplicateAsRoot; /// @@ -955,6 +956,8 @@ private bool InternalHasAuthority() /// bandwidth cost. This can also be useful for UI elements that have /// a predetermined fixed position. /// + [Tooltip("If enabled (default enabled), newly joining clients will be synchronized with the transform of the associated GameObject this component is attached to. Typical use case" + + " scenario would be for managment objects or in-scene placed objects that don't move and already have their transform settings applied within the scene information.")] public bool SynchronizeTransform = true; /// @@ -1012,6 +1015,7 @@ public void SetSceneObjectStatus(bool isSceneObject = false) /// To synchronize clients of a 's scene being changed via , /// make sure is enabled (it is by default). /// + [Tooltip("When enabled (default disabled), spawned instances of this NetworkObject will automatically migrate to any newly assigned active scene.")] public bool ActiveSceneSynchronization; /// @@ -1030,6 +1034,7 @@ public void SetSceneObjectStatus(bool isSceneObject = false) /// is and is and the scene is not the currently /// active scene, then the will be destroyed. /// + [Tooltip("When enabled (default enabled), dynamically spawned instances of this NetworkObject's migration to a different scene will automatically be synchonize amongst clients.")] public bool SceneMigrationSynchronization = true; /// @@ -1045,7 +1050,7 @@ public void SetSceneObjectStatus(bool isSceneObject = false) /// /// When set to false, the NetworkObject will be spawned with no observers initially (other than the server) /// - [Tooltip("When false, the NetworkObject will spawn with no observers initially. (default is true)")] + [Tooltip("When disabled (default enabled), the NetworkObject will spawn with no observers. You control object visibility using NetworkShow. This applies to newly joining clients as well.")] public bool SpawnWithObservers = true; /// @@ -1074,11 +1079,13 @@ public void SetSceneObjectStatus(bool isSceneObject = false) /// Whether or not to destroy this object if it's owner is destroyed. /// If true, the objects ownership will be given to the server. /// + [Tooltip("When enabled (default disabled), instances of this NetworkObject will not be destroyed if the owning client disconnects.")] public bool DontDestroyWithOwner; /// /// Whether or not to enable automatic NetworkObject parent synchronization. /// + [Tooltip("When disabled (default enabled), NetworkObject parenting will not be automatically synchronized. This is typically used when you want to implement your own custom parenting solution.")] public bool AutoObjectParentSync = true; /// @@ -1091,12 +1098,14 @@ public void SetSceneObjectStatus(bool isSceneObject = false) /// When using a network topology and an owner authoritative motion model, disabling this can help smooth parenting transitions. /// When using a network topology this will have no impact on the owner's instance since only the authority/owner can parent. /// + [Tooltip("When disabled (default enabled), the owner will not apply a server or host's transform properties when parenting changes. Primarily useful for client-server network topology configurations.")] public bool SyncOwnerTransformWhenParented = true; /// /// Client-Server specific, when enabled an owner of a NetworkObject can parent locally as opposed to requiring the owner to notify the server it would like to be parented. /// This behavior is always true when using a distributed authority network topology and does not require it to be set. /// + [Tooltip("When enabled (default disabled), owner's can parent a NetworkObject locally without having to send an RPC to the server or host. Only pertinent when using client-server network topology configurations.")] public bool AllowOwnerToParent; internal readonly HashSet Observers = new HashSet(); diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ProxyMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ProxyMessage.cs index c7322c499e..57c8345175 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ProxyMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ProxyMessage.cs @@ -1,4 +1,3 @@ -using System; using Unity.Collections; namespace Unity.Netcode @@ -34,21 +33,13 @@ public unsafe void Handle(ref NetworkContext context) var networkManager = (NetworkManager)context.SystemOwner; if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(WrappedMessage.Metadata.NetworkObjectId, out var networkObject)) { - // With distributed authority mode, we can send Rpcs before we have been notified the NetworkObject is despawned. - // DANGO-TODO: Should the CMB Service cull out any Rpcs targeting recently despawned NetworkObjects? - // DANGO-TODO: This would require the service to keep track of despawned NetworkObjects since we re-use NetworkObject identifiers. - if (networkManager.DistributedAuthorityMode) + // If the NetworkObject no longer exists then just log a warning when developer mode logging is enabled and exit. + // This can happen if NetworkObject is despawned and a client sends an RPC before receiving the despawn message. + if (networkManager.LogLevel == LogLevel.Developer) { - if (networkManager.LogLevel == LogLevel.Developer) - { - NetworkLog.LogWarning($"[{WrappedMessage.Metadata.NetworkObjectId}, {WrappedMessage.Metadata.NetworkBehaviourId}, {WrappedMessage.Metadata.NetworkRpcMethodId}]An RPC called on a {nameof(NetworkObject)} that is not in the spawned objects list. Please make sure the {nameof(NetworkObject)} is spawned before calling RPCs."); - } - return; - } - else - { - throw new InvalidOperationException($"[{WrappedMessage.Metadata.NetworkObjectId}, {WrappedMessage.Metadata.NetworkBehaviourId}, {WrappedMessage.Metadata.NetworkRpcMethodId}]An RPC called on a {nameof(NetworkObject)} that is not in the spawned objects list. Please make sure the {nameof(NetworkObject)} is spawned before calling RPCs."); + NetworkLog.LogWarning($"[{WrappedMessage.Metadata.NetworkObjectId}, {WrappedMessage.Metadata.NetworkBehaviourId}, {WrappedMessage.Metadata.NetworkRpcMethodId}] An RPC called on a {nameof(NetworkObject)} that is not in the spawned objects list. Please make sure the {nameof(NetworkObject)} is spawned before calling RPCs."); } + return; } var observers = networkObject.Observers; diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/RpcMessages.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/RpcMessages.cs index ba207e1046..70e4c2aadf 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/RpcMessages.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/RpcMessages.cs @@ -60,7 +60,13 @@ public static void Handle(ref NetworkContext context, ref RpcMetadata metadata, var networkManager = (NetworkManager)context.SystemOwner; if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(metadata.NetworkObjectId, out var networkObject)) { - throw new InvalidOperationException($"An RPC called on a {nameof(NetworkObject)} that is not in the spawned objects list. Please make sure the {nameof(NetworkObject)} is spawned before calling RPCs."); + // If the NetworkObject no longer exists then just log a warning when developer mode logging is enabled and exit. + // This can happen if NetworkObject is despawned and a client sends an RPC before receiving the despawn message. + if (networkManager.LogLevel == LogLevel.Developer) + { + NetworkLog.LogWarning($"[{metadata.NetworkObjectId}, {metadata.NetworkBehaviourId}, {metadata.NetworkRpcMethodId}] An RPC called on a {nameof(NetworkObject)} that is not in the spawned objects list. Please make sure the {nameof(NetworkObject)} is spawned before calling RPCs."); + } + return; } var networkBehaviour = networkObject.GetNetworkBehaviourAtOrderIndex(metadata.NetworkBehaviourId);