The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.0.0-pre.4] - 2021-01-04 ### Added - Added `com.unity.modules.physics` and `com.unity.modules.physics2d` package dependencies (#1565) ### Removed - Removed `com.unity.modules.ai` package dependency (#1565) - Removed `FixedQueue`, `StreamExtensions`, `TypeExtensions` (#1398) ### Fixed - Fixed in-scene NetworkObjects that are moved into the DDOL scene not getting restored to their original active state (enabled/disabled) after a full scene transition (#1354) - Fixed invalid IL code being generated when using `this` instead of `this ref` for the FastBufferReader/FastBufferWriter parameter of an extension method. (#1393) - Fixed an issue where if you are running as a server (not host) the LoadEventCompleted and UnloadEventCompleted events would fire early by the NetworkSceneManager (#1379) - Fixed a runtime error when sending an array of an INetworkSerializable type that's implemented as a struct (#1402) - NetworkConfig will no longer throw an OverflowException in GetConfig() when ForceSamePrefabs is enabled and the number of prefabs causes the config blob size to exceed 1300 bytes. (#1385) - Fixed NetworkVariable not calling NetworkSerialize on INetworkSerializable types (#1383) - Fixed NullReferenceException on ImportReferences call in NetworkBehaviourILPP (#1434) - Fixed NetworkObjects not being despawned before they are destroyed during shutdown for client, host, and server instances. (#1390) - Fixed KeyNotFound exception when removing ownership of a newly spawned NetworkObject that is already owned by the server. (#1500) - Fixed NetworkManager.LocalClient not being set when starting as a host. (#1511) - Fixed a few memory leak cases when shutting down NetworkManager during Incoming Message Queue processing. (#1323) ### Changed - The SDK no longer limits message size to 64k. (The transport may still impose its own limits, but the SDK no longer does.) (#1384) - Updated com.unity.collections to 1.1.0 (#1451)
181 lines
7.1 KiB
C#
181 lines
7.1 KiB
C#
using UnityEngine;
|
|
using System;
|
|
|
|
namespace Unity.Netcode
|
|
{
|
|
/// <summary>
|
|
/// A variable that can be synchronized over the network.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class NetworkVariable<T> : NetworkVariableBase where T : unmanaged
|
|
{
|
|
// Functions that know how to serialize INetworkSerializable
|
|
internal static void WriteNetworkSerializable<TForMethod>(FastBufferWriter writer, ref TForMethod value)
|
|
where TForMethod : INetworkSerializable, new()
|
|
{
|
|
writer.WriteNetworkSerializable(value);
|
|
}
|
|
internal static void ReadNetworkSerializable<TForMethod>(FastBufferReader reader, out TForMethod value)
|
|
where TForMethod : INetworkSerializable, new()
|
|
{
|
|
reader.ReadNetworkSerializable(out value);
|
|
}
|
|
|
|
// Functions that serialize other types
|
|
private static void WriteValue<TForMethod>(FastBufferWriter writer, ref TForMethod value) where TForMethod : unmanaged
|
|
{
|
|
writer.WriteValueSafe(value);
|
|
}
|
|
|
|
private static void ReadValue<TForMethod>(FastBufferReader reader, out TForMethod value)
|
|
where TForMethod : unmanaged
|
|
{
|
|
reader.ReadValueSafe(out value);
|
|
}
|
|
|
|
internal delegate void WriteDelegate<TForMethod>(FastBufferWriter writer, ref TForMethod value);
|
|
|
|
internal delegate void ReadDelegate<TForMethod>(FastBufferReader reader, out TForMethod value);
|
|
|
|
// These static delegates provide the right implementation for writing and reading a particular network variable
|
|
// type.
|
|
//
|
|
// For most types, these default to WriteValue() and ReadValue(), which perform simple memcpy operations.
|
|
//
|
|
// INetworkSerializableILPP will generate startup code that will set it to WriteNetworkSerializable()
|
|
// and ReadNetworkSerializable() for INetworkSerializable types, which will call NetworkSerialize().
|
|
//
|
|
// In the future we may be able to use this to provide packing implementations for floats and integers to
|
|
// optimize bandwidth usage.
|
|
//
|
|
// The reason this is done is to avoid runtime reflection and boxing in NetworkVariable - without this,
|
|
// NetworkVariable would need to do a `var is INetworkSerializable` check, and then cast to INetworkSerializable,
|
|
// *both* of which would cause a boxing allocation. Alternatively, NetworkVariable could have been split into
|
|
// NetworkVariable and NetworkSerializableVariable or something like that, which would have caused a poor
|
|
// user experience and an API that's easier to get wrong than right. This is a bit ugly on the implementation
|
|
// side, but it gets the best achievable user experience and performance.
|
|
internal static WriteDelegate<T> Write = WriteValue;
|
|
internal static ReadDelegate<T> Read = ReadValue;
|
|
|
|
|
|
/// <summary>
|
|
/// Delegate type for value changed event
|
|
/// </summary>
|
|
/// <param name="previousValue">The value before the change</param>
|
|
/// <param name="newValue">The new value</param>
|
|
public delegate void OnValueChangedDelegate(T previousValue, T newValue);
|
|
/// <summary>
|
|
/// The callback to be invoked when the value gets changed
|
|
/// </summary>
|
|
public OnValueChangedDelegate OnValueChanged;
|
|
|
|
/// <summary>
|
|
/// Creates a NetworkVariable with the default value and custom read permission
|
|
/// </summary>
|
|
/// <param name="readPerm">The read permission for the NetworkVariable</param>
|
|
|
|
public NetworkVariable()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a NetworkVariable with the default value and custom read permission
|
|
/// </summary>
|
|
/// <param name="readPerm">The read permission for the NetworkVariable</param>
|
|
public NetworkVariable(NetworkVariableReadPermission readPerm) : base(readPerm)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a NetworkVariable with a custom value and custom settings
|
|
/// </summary>
|
|
/// <param name="readPerm">The read permission for the NetworkVariable</param>
|
|
/// <param name="value">The initial value to use for the NetworkVariable</param>
|
|
public NetworkVariable(NetworkVariableReadPermission readPerm, T value) : base(readPerm)
|
|
{
|
|
m_InternalValue = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a NetworkVariable with a custom value and the default read permission
|
|
/// </summary>
|
|
/// <param name="value">The initial value to use for the NetworkVariable</param>
|
|
public NetworkVariable(T value)
|
|
{
|
|
m_InternalValue = value;
|
|
}
|
|
|
|
[SerializeField]
|
|
private protected T m_InternalValue;
|
|
|
|
/// <summary>
|
|
/// The value of the NetworkVariable container
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes the variable to the writer
|
|
/// </summary>
|
|
/// <param name="writer">The stream to write the value to</param>
|
|
public override void WriteDelta(FastBufferWriter writer)
|
|
{
|
|
WriteField(writer);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Reads value from the reader and applies it
|
|
/// </summary>
|
|
/// <param name="reader">The stream to read the value from</param>
|
|
/// <param name="keepDirtyDelta">Whether or not the container should keep the dirty delta, or mark the delta as consumed</param>
|
|
public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
|
|
{
|
|
T previousValue = m_InternalValue;
|
|
Read(reader, out m_InternalValue);
|
|
|
|
if (keepDirtyDelta)
|
|
{
|
|
m_IsDirty = true;
|
|
}
|
|
|
|
OnValueChanged?.Invoke(previousValue, m_InternalValue);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void ReadField(FastBufferReader reader)
|
|
{
|
|
Read(reader, out m_InternalValue);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void WriteField(FastBufferWriter writer)
|
|
{
|
|
Write(writer, ref m_InternalValue);
|
|
}
|
|
}
|
|
}
|