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);
}
}