using System; using System.Runtime.CompilerServices; using UnityEngine; namespace Unity.Netcode { /// /// A helper struct for serializing s over the network. Can be used in RPCs and . /// public struct NetworkObjectReference : INetworkSerializable, IEquatable { private ulong m_NetworkObjectId; /// /// The of the referenced . /// public ulong NetworkObjectId { get => m_NetworkObjectId; internal set => m_NetworkObjectId = value; } /// /// Creates a new instance of the struct. /// /// The to reference. /// /// public NetworkObjectReference(NetworkObject networkObject) { if (networkObject == null) { throw new ArgumentNullException(nameof(networkObject)); } if (networkObject.IsSpawned == false) { throw new ArgumentException($"{nameof(NetworkObjectReference)} can only be created from spawned {nameof(NetworkObject)}s."); } m_NetworkObjectId = networkObject.NetworkObjectId; } /// /// Creates a new instance of the struct. /// /// The GameObject from which the component will be referenced. /// /// public NetworkObjectReference(GameObject gameObject) { if (gameObject == null) { throw new ArgumentNullException(nameof(gameObject)); } var networkObject = gameObject.GetComponent(); if (networkObject == null) { throw new ArgumentException($"Cannot create {nameof(NetworkObjectReference)} from {nameof(GameObject)} without a {nameof(NetworkObject)} component."); } if (networkObject.IsSpawned == false) { throw new ArgumentException($"{nameof(NetworkObjectReference)} can only be created from spawned {nameof(NetworkObject)}s."); } m_NetworkObjectId = networkObject.NetworkObjectId; } /// /// Tries to get the referenced by this reference. /// /// The which was found. Null if no object was found. /// The networkmanager. Uses to resolve if null. /// True if the was found; False if the was not found. This can happen if the has not been spawned yet. you can try getting the reference at a later point in time. public bool TryGet(out NetworkObject networkObject, NetworkManager networkManager = null) { networkObject = Resolve(this, networkManager); return networkObject != null; } /// /// Resolves the corresponding for this reference. /// /// The reference. /// The networkmanager. Uses to resolve if null. /// The resolves . Returns null if the networkobject was not found [MethodImpl(MethodImplOptions.AggressiveInlining)] private static NetworkObject Resolve(NetworkObjectReference networkObjectRef, NetworkManager networkManager = null) { networkManager = networkManager != null ? networkManager : NetworkManager.Singleton; networkManager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectRef.m_NetworkObjectId, out NetworkObject networkObject); return networkObject; } /// public bool Equals(NetworkObjectReference other) { return m_NetworkObjectId == other.m_NetworkObjectId; } /// public override bool Equals(object obj) { return obj is NetworkObjectReference other && Equals(other); } /// public override int GetHashCode() { return m_NetworkObjectId.GetHashCode(); } /// public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { serializer.SerializeValue(ref m_NetworkObjectId); } /// /// Implicitly convert to . /// /// The to convert from. /// The the is referencing public static implicit operator NetworkObject(NetworkObjectReference networkObjectRef) => Resolve(networkObjectRef); /// /// Implicitly convert to . /// /// The to convert from. /// The created from the parameter public static implicit operator NetworkObjectReference(NetworkObject networkObject) => new NetworkObjectReference(networkObject); /// /// Implicitly convert to . /// /// The to convert from. /// This returns the that the is attached to and is referenced by the passed in as a parameter public static implicit operator GameObject(NetworkObjectReference networkObjectRef) { var networkObject = Resolve(networkObjectRef); if (networkObject != null) { return networkObject.gameObject; } return null; } /// /// Implicitly convert to . /// /// The to convert from. /// The created from the parameter that has a component attached to it public static implicit operator NetworkObjectReference(GameObject gameObject) => new NetworkObjectReference(gameObject); } }