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