using System; using System.Runtime.CompilerServices; namespace Unity.Netcode { /// /// A helper struct for serializing s over the network. Can be used in RPCs and . /// Note: network ids get recycled by the NetworkManager after a while. So a reference pointing to /// public struct NetworkBehaviourReference : INetworkSerializable, IEquatable { private NetworkObjectReference m_NetworkObjectReference; private ushort m_NetworkBehaviourId; /// /// Creates a new instance of the struct. /// /// The to reference. /// public NetworkBehaviourReference(NetworkBehaviour networkBehaviour) { if (networkBehaviour == null) { throw new ArgumentNullException(nameof(networkBehaviour)); } if (networkBehaviour.NetworkObject == null) { throw new ArgumentException($"Cannot create {nameof(NetworkBehaviourReference)} from {nameof(NetworkBehaviour)} without a {nameof(NetworkObject)}."); } m_NetworkObjectReference = networkBehaviour.NetworkObject; m_NetworkBehaviourId = networkBehaviour.NetworkBehaviourId; } /// /// Tries to get the referenced by this reference. /// /// The which was found. Null if the corresponding was not found. /// The networkmanager. Uses to resolve if null. /// True if the was found; False if the was not found. This can happen if the corresponding has not been spawned yet. you can try getting the reference at a later point in time. public bool TryGet(out NetworkBehaviour networkBehaviour, NetworkManager networkManager = null) { networkBehaviour = GetInternal(this, null); return networkBehaviour != null; } /// /// Tries to get the referenced by this reference. /// /// The which was found. Null if the corresponding was not found. /// The networkmanager. Uses to resolve if null. /// The type of the networkBehaviour for convenience. /// True if the was found; False if the was not found. This can happen if the corresponding has not been spawned yet. you can try getting the reference at a later point in time. public bool TryGet(out T networkBehaviour, NetworkManager networkManager = null) where T : NetworkBehaviour { networkBehaviour = GetInternal(this, null) as T; return networkBehaviour != null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static NetworkBehaviour GetInternal(NetworkBehaviourReference networkBehaviourRef, NetworkManager networkManager = null) { if (networkBehaviourRef.m_NetworkObjectReference.TryGet(out NetworkObject networkObject, networkManager)) { return networkObject.GetNetworkBehaviourAtOrderIndex(networkBehaviourRef.m_NetworkBehaviourId); } return null; } /// public bool Equals(NetworkBehaviourReference other) { return m_NetworkObjectReference.Equals(other.m_NetworkObjectReference) && m_NetworkBehaviourId == other.m_NetworkBehaviourId; } /// public override bool Equals(object obj) { return obj is NetworkBehaviourReference other && Equals(other); } /// public override int GetHashCode() { unchecked { return (m_NetworkObjectReference.GetHashCode() * 397) ^ m_NetworkBehaviourId.GetHashCode(); } } /// public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { m_NetworkObjectReference.NetworkSerialize(serializer); serializer.SerializeValue(ref m_NetworkBehaviourId); } /// /// Implicitly convert to . /// /// The to convert from. /// The this class is holding a reference to public static implicit operator NetworkBehaviour(NetworkBehaviourReference networkBehaviourRef) => GetInternal(networkBehaviourRef); /// /// Implicitly convert to . /// /// The to convert from. /// The created from the passed in as a parameter public static implicit operator NetworkBehaviourReference(NetworkBehaviour networkBehaviour) => new NetworkBehaviourReference(networkBehaviour); } }