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