using UnityEngine; using System; namespace Unity.Netcode { /// /// A variable that can be synchronized over the network. /// [Serializable] public class NetworkVariable : NetworkVariableBase where T : unmanaged { /// /// Delegate type for value changed event /// /// The value before the change /// The new value public delegate void OnValueChangedDelegate(T previousValue, T newValue); /// /// The callback to be invoked when the value gets changed /// public OnValueChangedDelegate OnValueChanged; /// /// Creates a NetworkVariable with the default value and custom read permission /// /// The read permission for the NetworkVariable public NetworkVariable() { } /// /// Creates a NetworkVariable with the default value and custom read permission /// /// The read permission for the NetworkVariable public NetworkVariable(NetworkVariableReadPermission readPerm) : base(readPerm) { } /// /// Creates a NetworkVariable with a custom value and custom settings /// /// The read permission for the NetworkVariable /// The initial value to use for the NetworkVariable public NetworkVariable(NetworkVariableReadPermission readPerm, T value) : base(readPerm) { m_InternalValue = value; } /// /// Creates a NetworkVariable with a custom value and the default read permission /// /// The initial value to use for the NetworkVariable public NetworkVariable(T value) { m_InternalValue = value; } [SerializeField] private protected T m_InternalValue; /// /// The value of the NetworkVariable container /// public virtual T Value { get => m_InternalValue; set { // this could be improved. The Networking Manager is not always initialized here // Good place to decouple network manager from the network variable // Also, note this is not really very water-tight, if you are running as a host // we cannot tell if a NetworkVariable write is happening inside client-ish code if (m_NetworkBehaviour && (m_NetworkBehaviour.NetworkManager.IsClient && !m_NetworkBehaviour.NetworkManager.IsHost)) { throw new InvalidOperationException("Client can't write to NetworkVariables"); } Set(value); } } private protected void Set(T value) { m_IsDirty = true; T previousValue = m_InternalValue; m_InternalValue = value; OnValueChanged?.Invoke(previousValue, m_InternalValue); } /// /// Writes the variable to the writer /// /// The stream to write the value to public override void WriteDelta(FastBufferWriter writer) { WriteField(writer); } /// /// Reads value from the reader and applies it /// /// The stream to read the value from /// Whether or not the container should keep the dirty delta, or mark the delta as consumed public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta) { T previousValue = m_InternalValue; reader.ReadValueSafe(out m_InternalValue); if (keepDirtyDelta) { m_IsDirty = true; } OnValueChanged?.Invoke(previousValue, m_InternalValue); } /// public override void ReadField(FastBufferReader reader) { reader.ReadValueSafe(out m_InternalValue); } /// public override void WriteField(FastBufferWriter writer) { writer.WriteValueSafe(m_InternalValue); } } }