using System; using UnityEngine; namespace Unity.Netcode { /// /// Interface for network value containers /// public abstract class NetworkVariableBase : IDisposable { /// /// The delivery type (QoS) to send data with /// internal const NetworkDelivery Delivery = NetworkDelivery.ReliableFragmentedSequenced; /// /// Maintains a link to the associated NetworkBehaviour /// private protected NetworkBehaviour m_NetworkBehaviour; private NetworkManager m_InternalNetworkManager; internal virtual NetworkVariableType Type => NetworkVariableType.Custom; private protected NetworkManager m_NetworkManager { get { if (m_InternalNetworkManager == null && m_NetworkBehaviour && m_NetworkBehaviour.NetworkObject?.NetworkManager) { m_InternalNetworkManager = m_NetworkBehaviour.NetworkObject?.NetworkManager; } return m_InternalNetworkManager; } } public NetworkBehaviour GetBehaviour() { return m_NetworkBehaviour; } /// /// Initializes the NetworkVariable /// /// The NetworkBehaviour the NetworkVariable belongs to public void Initialize(NetworkBehaviour networkBehaviour) { m_InternalNetworkManager = null; m_NetworkBehaviour = networkBehaviour; if (m_NetworkBehaviour && m_NetworkBehaviour.NetworkObject?.NetworkManager) { m_InternalNetworkManager = m_NetworkBehaviour.NetworkObject?.NetworkManager; // When in distributed authority mode, there is no such thing as server write permissions InternalWritePerm = m_InternalNetworkManager.DistributedAuthorityMode ? NetworkVariableWritePermission.Owner : InternalWritePerm; } } /// /// The default read permissions /// public const NetworkVariableReadPermission DefaultReadPerm = NetworkVariableReadPermission.Everyone; /// /// The default write permissions /// public const NetworkVariableWritePermission DefaultWritePerm = NetworkVariableWritePermission.Server; /// /// The default constructor for that can be used to create a /// custom NetworkVariable. /// /// the access settings /// the access settings protected NetworkVariableBase( NetworkVariableReadPermission readPerm = DefaultReadPerm, NetworkVariableWritePermission writePerm = DefaultWritePerm) { ReadPerm = readPerm; InternalWritePerm = writePerm; } /// /// The property is used to determine if the /// value of the `NetworkVariable` has changed. /// private bool m_IsDirty; /// /// Gets or sets the name of the network variable's instance /// (MemberInfo) where it was declared. /// public string Name { get; internal set; } /// /// The read permission for this var /// public readonly NetworkVariableReadPermission ReadPerm; /// /// The write permission for this var /// public NetworkVariableWritePermission WritePerm { get { return InternalWritePerm; } } // We had to change the Write Permission in distributed authority. // (It is too bad we initially declared it as readonly) internal NetworkVariableWritePermission InternalWritePerm; /// /// Sets whether or not the variable needs to be delta synced /// /// Whether or not the var is dirty public virtual void SetDirty(bool isDirty) { m_IsDirty = isDirty; if (m_IsDirty) { MarkNetworkBehaviourDirty(); } } internal static bool IgnoreInitializeWarning; protected void MarkNetworkBehaviourDirty() { if (m_NetworkBehaviour == null) { if (!IgnoreInitializeWarning) { Debug.LogWarning($"NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. " + "Are you modifying a NetworkVariable before the NetworkObject is spawned?"); } return; } if (m_NetworkBehaviour.NetworkManager.ShutdownInProgress) { if (m_NetworkBehaviour.NetworkManager.LogLevel <= LogLevel.Developer) { Debug.LogWarning($"NetworkVariable is written to during the NetworkManager shutdown! " + "Are you modifying a NetworkVariable within a NetworkBehaviour.OnDestroy or NetworkBehaviour.OnDespawn method?"); } return; } m_NetworkBehaviour.NetworkManager.BehaviourUpdater?.AddForUpdate(m_NetworkBehaviour.NetworkObject); } /// /// Resets the dirty state and marks the variable as synced / clean /// public virtual void ResetDirty() { m_IsDirty = false; } /// /// Gets Whether or not the container is dirty /// /// Whether or not the container is dirty public virtual bool IsDirty() { return m_IsDirty; } /// /// Gets if a specific client has permission to read the var or not /// /// The client id /// Whether or not the client has permission to read public bool CanClientRead(ulong clientId) { // When in distributed authority mode, everyone can read (but only the owner can write) if (m_NetworkManager != null && m_NetworkManager.DistributedAuthorityMode) { return true; } switch (ReadPerm) { default: case NetworkVariableReadPermission.Everyone: return true; case NetworkVariableReadPermission.Owner: return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId || NetworkManager.ServerClientId == clientId; } } /// /// Gets if a specific client has permission to write the var or not /// /// The client id /// Whether or not the client has permission to write public bool CanClientWrite(ulong clientId) { switch (WritePerm) { default: case NetworkVariableWritePermission.Server: return clientId == NetworkManager.ServerClientId; case NetworkVariableWritePermission.Owner: return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId; } } /// /// Returns the ClientId of the owning client /// internal ulong OwnerClientId() { return m_NetworkBehaviour.NetworkObject.OwnerClientId; } /// /// Writes the dirty changes, that is, the changes since the variable was last dirty, to the writer /// /// The stream to write the dirty changes to public abstract void WriteDelta(FastBufferWriter writer); /// /// Writes the complete state of the variable to the writer /// /// The stream to write the state to public abstract void WriteField(FastBufferWriter writer); /// /// Reads the complete state from the reader and applies it /// /// The stream to read the state from public abstract void ReadField(FastBufferReader reader); /// /// Reads delta from the reader and applies them to the internal value /// /// The stream to read the delta from /// Whether or not the delta should be kept as dirty or consumed public abstract void ReadDelta(FastBufferReader reader, bool keepDirtyDelta); /// /// Virtual implementation /// public virtual void Dispose() { m_InternalNetworkManager = null; } } /// /// Enum representing the different types of Network Variables. /// public enum NetworkVariableType : byte { /// /// Value /// Used for all of the basic NetworkVariables that contain a single value /// Value = 0, /// /// Custom /// For any custom implemented extension of the NetworkVariableBase /// Custom = 1, /// /// NetworkList /// NetworkList = 2 } public enum CollectionItemType : byte { /// /// For any type that is not valid inside a NetworkVariable collection /// Unknown = 0, /// /// The following types are valid types inside of NetworkVariable collections /// Short = 1, UShort = 2, Int = 3, UInt = 4, Long = 5, ULong = 6, Unmanaged = 7, } }