From d709df42050580392a3a6caeeff919e54a8ac935 Mon Sep 17 00:00:00 2001 From: Noel Stephens Date: Mon, 4 Nov 2024 13:08:40 -0600 Subject: [PATCH] fix: send to not owner server warning message (#3111) * fix When sending to not owner, use the not authority target when using a distributed authority network topology. * fix When sending to owner, use the authority target when using a distributed authority network topology. * update adding change log entry * fix This resolves the remaining issues with universal rpcs when using a distributed authority network topology. --- com.unity.netcode.gameobjects/CHANGELOG.md | 1 + .../RpcTargets/ClientsAndHostRpcTarget.cs | 3 +- .../Messaging/RpcTargets/NotOwnerRpcTarget.cs | 10 ++++ .../RpcTargets/NotServerRpcTarget.cs | 8 ++- .../Messaging/RpcTargets/OwnerRpcTarget.cs | 11 ++++ .../Messaging/RpcTargets/ServerRpcTarget.cs | 53 ++++++++++++++++++- 6 files changed, 83 insertions(+), 3 deletions(-) diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 2c2df03c8c..fd4ae80745 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Fixed +- Fixed issue where `NotOwnerRpcTarget` or `OwnerRpcTarget` were not using their replacements `NotAuthorityRpcTarget` and `AuthorityRpcTarget` which would invoke a warning. (#3111) - Fixed issue where client is removed as an observer from spawned objects when their player instance is despawned. (#3110) - Fixed issue where `NetworkAnimator` would statically allocate write buffer space for `Animator` parameters that could cause a write error if the number of parameters exceeded the space allocated. (#3108) diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ClientsAndHostRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ClientsAndHostRpcTarget.cs index 286b0b0134..373e43f4fe 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ClientsAndHostRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ClientsAndHostRpcTarget.cs @@ -17,7 +17,8 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, // ClientsAndHost sends to everyone who runs any client logic // So if the server is a host, this target includes it (as hosts run client logic) // If the server is not a host, this target leaves it out, ergo the selection of NotServer. - if (behaviour.NetworkManager.ServerIsHost) + // If we are in distributed authority mode and connected to a service, then send to all clients. + if (behaviour.NetworkManager.ServerIsHost || (m_NetworkManager.DistributedAuthorityMode && m_NetworkManager.CMBServiceConnection)) { m_UnderlyingTarget = behaviour.RpcTarget.Everyone; } diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotOwnerRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotOwnerRpcTarget.cs index e4f64f0530..348c1af313 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotOwnerRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotOwnerRpcTarget.cs @@ -4,12 +4,14 @@ internal class NotOwnerRpcTarget : BaseRpcTarget { private IGroupRpcTarget m_GroupSendTarget; private ServerRpcTarget m_ServerRpcTarget; + private NotAuthorityRpcTarget m_NotAuthorityRpcTarget; private LocalSendRpcTarget m_LocalSendRpcTarget; public override void Dispose() { m_ServerRpcTarget.Dispose(); m_LocalSendRpcTarget.Dispose(); + m_NotAuthorityRpcTarget.Dispose(); if (m_GroupSendTarget != null) { m_GroupSendTarget.Target.Dispose(); @@ -19,6 +21,13 @@ public override void Dispose() internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, NetworkDelivery delivery, RpcParams rpcParams) { + // Not owner is the same as not authority in distributed authority mode + if (m_NetworkManager.DistributedAuthorityMode) + { + m_NotAuthorityRpcTarget.Send(behaviour, ref message, delivery, rpcParams); + return; + } + if (m_GroupSendTarget == null) { if (behaviour.IsServer) @@ -86,6 +95,7 @@ internal NotOwnerRpcTarget(NetworkManager manager) : base(manager) { m_ServerRpcTarget = new ServerRpcTarget(manager); m_LocalSendRpcTarget = new LocalSendRpcTarget(manager); + m_NotAuthorityRpcTarget = new NotAuthorityRpcTarget(manager); } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotServerRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotServerRpcTarget.cs index 30b745e68c..3ac0b231a9 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotServerRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotServerRpcTarget.cs @@ -51,7 +51,13 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, continue; } - if (clientId == behaviour.NetworkManager.LocalClientId) + // If we are in distributed authority mode and connected to the service, then we exclude the owner/authority from the list + if (m_NetworkManager.DistributedAuthorityMode && m_NetworkManager.CMBServiceConnection && clientId == behaviour.OwnerClientId) + { + continue; + } + + if (clientId == m_NetworkManager.LocalClientId) { m_LocalSendRpcTarget.Send(behaviour, ref message, delivery, rpcParams); continue; diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/OwnerRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/OwnerRpcTarget.cs index 7c7829402d..e22c588ef3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/OwnerRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/OwnerRpcTarget.cs @@ -5,9 +5,12 @@ internal class OwnerRpcTarget : BaseRpcTarget private IIndividualRpcTarget m_UnderlyingTarget; private LocalSendRpcTarget m_LocalRpcTarget; private ServerRpcTarget m_ServerRpcTarget; + private AuthorityRpcTarget m_AuthorityRpcTarget; public override void Dispose() { + m_AuthorityRpcTarget.Dispose(); + m_ServerRpcTarget.Dispose(); m_LocalRpcTarget.Dispose(); if (m_UnderlyingTarget != null) { @@ -18,6 +21,13 @@ public override void Dispose() internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, NetworkDelivery delivery, RpcParams rpcParams) { + // Sending to owner is the same as sending to authority in distributed authority mode + if (m_NetworkManager.DistributedAuthorityMode) + { + m_AuthorityRpcTarget.Send(behaviour, ref message, delivery, rpcParams); + return; + } + if (behaviour.OwnerClientId == behaviour.NetworkManager.LocalClientId) { m_LocalRpcTarget.Send(behaviour, ref message, delivery, rpcParams); @@ -49,6 +59,7 @@ internal OwnerRpcTarget(NetworkManager manager) : base(manager) { m_LocalRpcTarget = new LocalSendRpcTarget(manager); m_ServerRpcTarget = new ServerRpcTarget(manager); + m_AuthorityRpcTarget = new AuthorityRpcTarget(manager); } } } diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ServerRpcTarget.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ServerRpcTarget.cs index 8ad53fb992..0db593f23b 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ServerRpcTarget.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/ServerRpcTarget.cs @@ -1,8 +1,10 @@ +using Unity.Collections; namespace Unity.Netcode { internal class ServerRpcTarget : BaseRpcTarget { protected BaseRpcTarget m_UnderlyingTarget; + protected ProxyRpcTarget m_ProxyRpcTarget; public override void Dispose() { @@ -11,13 +13,62 @@ public override void Dispose() m_UnderlyingTarget.Dispose(); m_UnderlyingTarget = null; } + + if (m_ProxyRpcTarget != null) + { + m_ProxyRpcTarget.Dispose(); + m_ProxyRpcTarget = null; + } } internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message, NetworkDelivery delivery, RpcParams rpcParams) { + // For distributed authority the "server" is considered the authority of the object if (behaviour.NetworkManager.DistributedAuthorityMode && behaviour.NetworkManager.CMBServiceConnection) { - UnityEngine.Debug.LogWarning("[Invalid Target] There is no server to send to when in Distributed Authority mode!"); + // If the local instance is the owner, then invoke the message locally on this behaviour + if (behaviour.IsOwner) + { + var context = new NetworkContext + { + SenderId = m_NetworkManager.LocalClientId, + Timestamp = m_NetworkManager.RealTimeProvider.RealTimeSinceStartup, + SystemOwner = m_NetworkManager, + // header information isn't valid since it's not a real message. + // RpcMessage doesn't access this stuff so it's just left empty. + Header = new NetworkMessageHeader(), + SerializedHeaderSize = 0, + MessageSize = 0 + }; + using var tempBuffer = new FastBufferReader(message.WriteBuffer, Allocator.None); + message.ReadBuffer = tempBuffer; + message.Handle(ref context); + // If enabled, then add the RPC metrics for this +#if DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE + int length = tempBuffer.Length; + if (NetworkBehaviour.__rpc_name_table[behaviour.GetType()].TryGetValue(message.Metadata.NetworkRpcMethodId, out var rpcMethodName)) + { + m_NetworkManager.NetworkMetrics.TrackRpcSent( + m_NetworkManager.LocalClientId, + behaviour.NetworkObject, + rpcMethodName, + behaviour.__getTypeName(), + length); + } +#endif + } + else // Otherwise, send a proxied message to the owner of the object + { + if (m_ProxyRpcTarget == null) + { + m_ProxyRpcTarget = new ProxyRpcTarget(behaviour.OwnerClientId, m_NetworkManager); + } + else + { + m_ProxyRpcTarget.SetClientId(behaviour.OwnerClientId); + } + m_ProxyRpcTarget.Send(behaviour, ref message, delivery, rpcParams); + } return; }