com.unity.netcode.gameobjects@1.0.0

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] - 2022-06-27

### Changed

- Changed version to 1.0.0. (#2046)
This commit is contained in:
Unity Technologies
2022-06-27 00:00:00 +00:00
parent 0f7a30d285
commit 18ffd5fdc8
44 changed files with 2667 additions and 67 deletions

View File

@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).
## [1.0.0] - 2022-06-27
### Changed
- Changed version to 1.0.0. (#2046)
## [1.0.0-pre.10] - 2022-06-21 ## [1.0.0-pre.10] - 2022-06-21
### Added ### Added
@@ -18,7 +24,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Changed ### Changed
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025) - Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025)
- (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972) - (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now an `Action<>` taking a `ConnectionApprovalRequest` and a `ConnectionApprovalResponse` that the client code must fill (#1972) (#2002)
### Removed ### Removed

View File

@@ -8,6 +8,7 @@ namespace Unity.Netcode
/// Solves for incoming values that are jittered /// Solves for incoming values that are jittered
/// Partially solves for message loss. Unclamped lerping helps hide this, but not completely /// Partially solves for message loss. Unclamped lerping helps hide this, but not completely
/// </summary> /// </summary>
/// <typeparam name="T">The type of interpolated value</typeparam>
public abstract class BufferedLinearInterpolator<T> where T : struct public abstract class BufferedLinearInterpolator<T> where T : struct
{ {
internal float MaxInterpolationBound = 3.0f; internal float MaxInterpolationBound = 3.0f;
@@ -24,7 +25,7 @@ namespace Unity.Netcode
} }
/// <summary> /// <summary>
/// Theres two factors affecting interpolation: buffering (set in NetworkManagers NetworkTimeSystem) and interpolation time, which is the amount of time itll take to reach the target. This is to affect the second one. /// There's two factors affecting interpolation: buffering (set in NetworkManager's NetworkTimeSystem) and interpolation time, which is the amount of time it'll take to reach the target. This is to affect the second one.
/// </summary> /// </summary>
public float MaximumInterpolationTime = 0.1f; public float MaximumInterpolationTime = 0.1f;
@@ -73,7 +74,7 @@ namespace Unity.Netcode
private bool InvalidState => m_Buffer.Count == 0 && m_LifetimeConsumedCount == 0; private bool InvalidState => m_Buffer.Count == 0 && m_LifetimeConsumedCount == 0;
/// <summary> /// <summary>
/// Resets Interpolator to initial state /// Resets interpolator to initial state
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
@@ -85,6 +86,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Teleports current interpolation value to targetValue. /// Teleports current interpolation value to targetValue.
/// </summary> /// </summary>
/// <param name="targetValue">The target value to teleport instantly</param>
/// <param name="serverTime">The current server time</param>
public void ResetTo(T targetValue, double serverTime) public void ResetTo(T targetValue, double serverTime)
{ {
m_LifetimeConsumedCount = 1; m_LifetimeConsumedCount = 1;
@@ -159,6 +162,7 @@ namespace Unity.Netcode
/// </summary> /// </summary>
/// <param name="deltaTime">time since call</param> /// <param name="deltaTime">time since call</param>
/// <param name="serverTime">current server time</param> /// <param name="serverTime">current server time</param>
/// <returns>The newly interpolated value of type 'T'</returns>
public T Update(float deltaTime, NetworkTime serverTime) public T Update(float deltaTime, NetworkTime serverTime)
{ {
return Update(deltaTime, serverTime.TimeTicksAgo(1).Time, serverTime.Time); return Update(deltaTime, serverTime.TimeTicksAgo(1).Time, serverTime.Time);
@@ -170,6 +174,7 @@ namespace Unity.Netcode
/// <param name="deltaTime">time since last call</param> /// <param name="deltaTime">time since last call</param>
/// <param name="renderTime">our current time</param> /// <param name="renderTime">our current time</param>
/// <param name="serverTime">current server time</param> /// <param name="serverTime">current server time</param>
/// <returns>The newly interpolated value of type 'T'</returns>
public T Update(float deltaTime, double renderTime, double serverTime) public T Update(float deltaTime, double renderTime, double serverTime)
{ {
TryConsumeFromBuffer(renderTime, serverTime); TryConsumeFromBuffer(renderTime, serverTime);
@@ -222,6 +227,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Add measurements to be used during interpolation. These will be buffered before being made available to be displayed as "latest value". /// Add measurements to be used during interpolation. These will be buffered before being made available to be displayed as "latest value".
/// </summary> /// </summary>
/// <param name="newMeasurement">The new measurement value to use</param>
/// <param name="sentTime">The time to record for measurement</param>
public void AddMeasurement(T newMeasurement, double sentTime) public void AddMeasurement(T newMeasurement, double sentTime)
{ {
m_NbItemsReceivedThisFrame++; m_NbItemsReceivedThisFrame++;
@@ -251,6 +258,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Gets latest value from the interpolator. This is updated every update as time goes by. /// Gets latest value from the interpolator. This is updated every update as time goes by.
/// </summary> /// </summary>
/// <returns>The current interpolated value of type 'T'</returns>
public T GetInterpolatedValue() public T GetInterpolatedValue()
{ {
return m_CurrentInterpValue; return m_CurrentInterpValue;
@@ -259,33 +267,54 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Method to override and adapted to the generic type. This assumes interpolation for that value will be clamped. /// Method to override and adapted to the generic type. This assumes interpolation for that value will be clamped.
/// </summary> /// </summary>
/// <param name="start">The start value (min)</param>
/// <param name="end">The end value (max)</param>
/// <param name="time">The time value used to interpolate between start and end values (pos)</param>
/// <returns>The interpolated value</returns>
protected abstract T Interpolate(T start, T end, float time); protected abstract T Interpolate(T start, T end, float time);
/// <summary> /// <summary>
/// Method to override and adapted to the generic type. This assumes interpolation for that value will not be clamped. /// Method to override and adapted to the generic type. This assumes interpolation for that value will not be clamped.
/// </summary> /// </summary>
/// <param name="start">The start value (min)</param>
/// <param name="end">The end value (max)</param>
/// <param name="time">The time value used to interpolate between start and end values (pos)</param>
/// <returns>The interpolated value</returns>
protected abstract T InterpolateUnclamped(T start, T end, float time); protected abstract T InterpolateUnclamped(T start, T end, float time);
} }
/// <inheritdoc />
/// <remarks>
/// This is a buffered linear interpolator for a <see cref="float"/> type value
/// </remarks>
public class BufferedLinearInterpolatorFloat : BufferedLinearInterpolator<float> public class BufferedLinearInterpolatorFloat : BufferedLinearInterpolator<float>
{ {
/// <inheritdoc />
protected override float InterpolateUnclamped(float start, float end, float time) protected override float InterpolateUnclamped(float start, float end, float time)
{ {
return Mathf.LerpUnclamped(start, end, time); return Mathf.LerpUnclamped(start, end, time);
} }
/// <inheritdoc />
protected override float Interpolate(float start, float end, float time) protected override float Interpolate(float start, float end, float time)
{ {
return Mathf.Lerp(start, end, time); return Mathf.Lerp(start, end, time);
} }
} }
/// <inheritdoc />
/// <remarks>
/// This is a buffered linear interpolator for a <see cref="Quaternion"/> type value
/// </remarks>
public class BufferedLinearInterpolatorQuaternion : BufferedLinearInterpolator<Quaternion> public class BufferedLinearInterpolatorQuaternion : BufferedLinearInterpolator<Quaternion>
{ {
/// <inheritdoc />
protected override Quaternion InterpolateUnclamped(Quaternion start, Quaternion end, float time) protected override Quaternion InterpolateUnclamped(Quaternion start, Quaternion end, float time)
{ {
return Quaternion.SlerpUnclamped(start, end, time); return Quaternion.SlerpUnclamped(start, end, time);
} }
/// <inheritdoc />
protected override Quaternion Interpolate(Quaternion start, Quaternion end, float time) protected override Quaternion Interpolate(Quaternion start, Quaternion end, float time)
{ {
return Quaternion.SlerpUnclamped(start, end, time); return Quaternion.SlerpUnclamped(start, end, time);

View File

@@ -37,6 +37,7 @@ namespace Unity.Netcode.Components
m_SendTriggerUpdates.Clear(); m_SendTriggerUpdates.Clear();
} }
/// <inheritdoc />
public void NetworkUpdate(NetworkUpdateStage updateStage) public void NetworkUpdate(NetworkUpdateStage updateStage)
{ {
switch (updateStage) switch (updateStage)

View File

@@ -5,20 +5,46 @@ using UnityEngine;
namespace Unity.Netcode.Components namespace Unity.Netcode.Components
{ {
/// <summary> /// <summary>
/// A component for syncing transforms /// A component for syncing transforms.
/// NetworkTransform will read the underlying transform and replicate it to clients. /// NetworkTransform will read the underlying transform and replicate it to clients.
/// The replicated value will be automatically be interpolated (if active) and applied to the underlying GameObject's transform /// The replicated value will be automatically be interpolated (if active) and applied to the underlying GameObject's transform.
/// </summary> /// </summary>
[DisallowMultipleComponent] [DisallowMultipleComponent]
[AddComponentMenu("Netcode/" + nameof(NetworkTransform))] [AddComponentMenu("Netcode/" + nameof(NetworkTransform))]
[DefaultExecutionOrder(100000)] // this is needed to catch the update time after the transform was updated by user scripts [DefaultExecutionOrder(100000)] // this is needed to catch the update time after the transform was updated by user scripts
public class NetworkTransform : NetworkBehaviour public class NetworkTransform : NetworkBehaviour
{ {
/// <summary>
/// The default position change threshold value.
/// Any changes above this threshold will be replicated.
/// </summary>
public const float PositionThresholdDefault = 0.001f; public const float PositionThresholdDefault = 0.001f;
/// <summary>
/// The default rotation angle change threshold value.
/// Any changes above this threshold will be replicated.
/// </summary>
public const float RotAngleThresholdDefault = 0.01f; public const float RotAngleThresholdDefault = 0.01f;
/// <summary>
/// The default scale change threshold value.
/// Any changes above this threshold will be replicated.
/// </summary>
public const float ScaleThresholdDefault = 0.01f; public const float ScaleThresholdDefault = 0.01f;
/// <summary>
/// The handler delegate type that takes client requested changes and returns resulting changes handled by the server.
/// </summary>
/// <param name="pos">The position requested by the client.</param>
/// <param name="rot">The rotation requested by the client.</param>
/// <param name="scale">The scale requested by the client.</param>
/// <returns>The resulting position, rotation and scale changes after handling.</returns>
public delegate (Vector3 pos, Quaternion rotOut, Vector3 scale) OnClientRequestChangeDelegate(Vector3 pos, Quaternion rot, Vector3 scale); public delegate (Vector3 pos, Quaternion rotOut, Vector3 scale) OnClientRequestChangeDelegate(Vector3 pos, Quaternion rot, Vector3 scale);
/// <summary>
/// The handler that gets invoked when server receives a change from a client.
/// This handler would be useful for server to modify pos/rot/scale before applying client's request.
/// </summary>
public OnClientRequestChangeDelegate OnClientRequestChange; public OnClientRequestChangeDelegate OnClientRequestChange;
internal struct NetworkTransformState : INetworkSerializable internal struct NetworkTransformState : INetworkSerializable
@@ -244,15 +270,62 @@ namespace Unity.Netcode.Components
} }
} }
public bool SyncPositionX = true, SyncPositionY = true, SyncPositionZ = true; /// <summary>
public bool SyncRotAngleX = true, SyncRotAngleY = true, SyncRotAngleZ = true; /// Whether or not x component of position will be replicated
public bool SyncScaleX = true, SyncScaleY = true, SyncScaleZ = true; /// </summary>
public bool SyncPositionX = true;
/// <summary>
/// Whether or not y component of position will be replicated
/// </summary>
public bool SyncPositionY = true;
/// <summary>
/// Whether or not z component of position will be replicated
/// </summary>
public bool SyncPositionZ = true;
/// <summary>
/// Whether or not x component of rotation will be replicated
/// </summary>
public bool SyncRotAngleX = true;
/// <summary>
/// Whether or not y component of rotation will be replicated
/// </summary>
public bool SyncRotAngleY = true;
/// <summary>
/// Whether or not z component of rotation will be replicated
/// </summary>
public bool SyncRotAngleZ = true;
/// <summary>
/// Whether or not x component of scale will be replicated
/// </summary>
public bool SyncScaleX = true;
/// <summary>
/// Whether or not y component of scale will be replicated
/// </summary>
public bool SyncScaleY = true;
/// <summary>
/// Whether or not z component of scale will be replicated
/// </summary>
public bool SyncScaleZ = true;
/// <summary>
/// The current position threshold value
/// Any changes to the position that exceeds the current threshold value will be replicated
/// </summary>
public float PositionThreshold = PositionThresholdDefault; public float PositionThreshold = PositionThresholdDefault;
/// <summary>
/// The current rotation threshold value
/// Any changes to the rotation that exceeds the current threshold value will be replicated
/// Minimum Value: 0.001
/// Maximum Value: 360.0
/// </summary>
[Range(0.001f, 360.0f)] [Range(0.001f, 360.0f)]
public float RotAngleThreshold = RotAngleThresholdDefault; public float RotAngleThreshold = RotAngleThresholdDefault;
/// <summary>
/// The current scale threshold value
/// Any changes to the scale that exceeds the current threshold value will be replicated
/// </summary>
public float ScaleThreshold = ScaleThresholdDefault; public float ScaleThreshold = ScaleThresholdDefault;
/// <summary> /// <summary>
@@ -265,6 +338,10 @@ namespace Unity.Netcode.Components
public bool InLocalSpace = false; public bool InLocalSpace = false;
private bool m_LastInterpolateLocal = false; // was the last frame local private bool m_LastInterpolateLocal = false; // was the last frame local
/// <summary>
/// When enabled (default) interpolation is applied and when disabled no interpolation is applied
/// Note: can be changed during runtime.
/// </summary>
public bool Interpolate = true; public bool Interpolate = true;
private bool m_LastInterpolate = true; // was the last frame interpolated private bool m_LastInterpolate = true; // was the last frame interpolated
@@ -276,7 +353,17 @@ namespace Unity.Netcode.Components
/// </summary> /// </summary>
// This is public to make sure that users don't depend on this IsClient && IsOwner check in their code. If this logic changes in the future, we can make it invisible here // This is public to make sure that users don't depend on this IsClient && IsOwner check in their code. If this logic changes in the future, we can make it invisible here
public bool CanCommitToTransform { get; protected set; } public bool CanCommitToTransform { get; protected set; }
/// <summary>
/// Internally used by <see cref="NetworkTransform"/> to keep track of whether this <see cref="NetworkBehaviour"/> derived class instance
/// was instantiated on the server side or not.
/// </summary>
protected bool m_CachedIsServer; protected bool m_CachedIsServer;
/// <summary>
/// Internally used by <see cref="NetworkTransform"/> to keep track of the <see cref="NetworkManager"/> instance assigned to this
/// this <see cref="NetworkBehaviour"/> derived class instance.
/// </summary>
protected NetworkManager m_CachedNetworkManager; protected NetworkManager m_CachedNetworkManager;
private readonly NetworkVariable<NetworkTransformState> m_ReplicatedNetworkState = new NetworkVariable<NetworkTransformState>(new NetworkTransformState()); private readonly NetworkVariable<NetworkTransformState> m_ReplicatedNetworkState = new NetworkVariable<NetworkTransformState>(new NetworkTransformState());
@@ -716,6 +803,13 @@ namespace Unity.Netcode.Components
} }
} }
/// <summary>
/// Will set the maximum interpolation boundary for the interpolators of this <see cref="NetworkTransform"/> instance.
/// This value roughly translates to the maximum value of 't' in <see cref="Mathf.Lerp(float, float, float)"/> and
/// <see cref="Mathf.LerpUnclamped(float, float, float)"/> for all transform elements being monitored by
/// <see cref="NetworkTransform"/> (i.e. Position, Rotation, and Scale)
/// </summary>
/// <param name="maxInterpolationBound">Maximum time boundary that can be used in a frame when interpolating between two values</param>
public void SetMaxInterpolationBound(float maxInterpolationBound) public void SetMaxInterpolationBound(float maxInterpolationBound)
{ {
m_PositionXInterpolator.MaxInterpolationBound = maxInterpolationBound; m_PositionXInterpolator.MaxInterpolationBound = maxInterpolationBound;
@@ -750,6 +844,8 @@ namespace Unity.Netcode.Components
} }
} }
/// <inheritdoc/>
public override void OnNetworkSpawn() public override void OnNetworkSpawn()
{ {
// must set up m_Transform in OnNetworkSpawn because it's possible an object spawns but is disabled // must set up m_Transform in OnNetworkSpawn because it's possible an object spawns but is disabled
@@ -773,16 +869,19 @@ namespace Unity.Netcode.Components
Initialize(); Initialize();
} }
/// <inheritdoc/>
public override void OnNetworkDespawn() public override void OnNetworkDespawn()
{ {
m_ReplicatedNetworkState.OnValueChanged -= OnNetworkStateChanged; m_ReplicatedNetworkState.OnValueChanged -= OnNetworkStateChanged;
} }
/// <inheritdoc/>
public override void OnGainedOwnership() public override void OnGainedOwnership()
{ {
Initialize(); Initialize();
} }
/// <inheritdoc/>
public override void OnLostOwnership() public override void OnLostOwnership()
{ {
Initialize(); Initialize();
@@ -850,8 +949,7 @@ namespace Unity.Netcode.Components
[ServerRpc] [ServerRpc]
private void SetStateServerRpc(Vector3 pos, Quaternion rot, Vector3 scale, bool shouldTeleport) private void SetStateServerRpc(Vector3 pos, Quaternion rot, Vector3 scale, bool shouldTeleport)
{ {
// server has received this RPC request to move change transform. Give the server a chance to modify or // server has received this RPC request to move change transform. give the server a chance to modify or even reject the move
// even reject the move
if (OnClientRequestChange != null) if (OnClientRequestChange != null)
{ {
(pos, rot, scale) = OnClientRequestChange(pos, rot, scale); (pos, rot, scale) = OnClientRequestChange(pos, rot, scale);
@@ -862,8 +960,9 @@ namespace Unity.Netcode.Components
m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = shouldTeleport; m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = shouldTeleport;
} }
// todo this is currently in update, to be able to catch any transform changes. A FixedUpdate mode could be added to be less intense, but it'd be // todo: this is currently in update, to be able to catch any transform changes. A FixedUpdate mode could be added to be less intense, but it'd be
// conditional to users only making transform update changes in FixedUpdate. // conditional to users only making transform update changes in FixedUpdate.
/// <inheritdoc/>
protected virtual void Update() protected virtual void Update()
{ {
if (!IsSpawned) if (!IsSpawned)
@@ -921,6 +1020,10 @@ namespace Unity.Netcode.Components
/// <summary> /// <summary>
/// Teleports the transform to the given values without interpolating /// Teleports the transform to the given values without interpolating
/// </summary> /// </summary>
/// <param name="newPosition"></param> new position to move to.
/// <param name="newRotation"></param> new rotation to rotate to.
/// <param name="newScale">new scale to scale to.</param>
/// <exception cref="Exception"></exception>
public void Teleport(Vector3 newPosition, Quaternion newRotation, Vector3 newScale) public void Teleport(Vector3 newPosition, Quaternion newRotation, Vector3 newScale)
{ {
if (!CanCommitToTransform) if (!CanCommitToTransform)
@@ -945,6 +1048,7 @@ namespace Unity.Netcode.Components
/// <summary> /// <summary>
/// Override this method and return false to switch to owner authoritative mode /// Override this method and return false to switch to owner authoritative mode
/// </summary> /// </summary>
/// <returns>(<see cref="true"/> or <see cref="false"/>) where when false it runs as owner-client authoritative</returns>
protected virtual bool OnIsServerAuthoritative() protected virtual bool OnIsServerAuthoritative()
{ {
return true; return true;

View File

@@ -151,6 +151,8 @@ namespace Unity.Netcode.Editor
} }
} }
/// <inheritdoc/>
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
if (!m_Initialized) if (!m_Initialized)
@@ -230,6 +232,11 @@ namespace Unity.Netcode.Editor
internal const string AutoAddNetworkObjectIfNoneExists = "AutoAdd-NetworkObject-When-None-Exist"; internal const string AutoAddNetworkObjectIfNoneExists = "AutoAdd-NetworkObject-When-None-Exist";
/// <summary>
/// Recursively finds the root parent of a <see cref="Transform"/>
/// </summary>
/// <param name="transform">The current <see cref="Transform"/> we are inspecting for a parent</param>
/// <returns>the root parent for the first <see cref="Transform"/> passed into the method</returns>
public static Transform GetRootParentTransform(Transform transform) public static Transform GetRootParentTransform(Transform transform)
{ {
if (transform.parent == null || transform.parent == transform) if (transform.parent == null || transform.parent == transform)
@@ -244,6 +251,8 @@ namespace Unity.Netcode.Editor
/// does not already have a NetworkObject component. If not it will notify /// does not already have a NetworkObject component. If not it will notify
/// the user that NetworkBehaviours require a NetworkObject. /// the user that NetworkBehaviours require a NetworkObject.
/// </summary> /// </summary>
/// <param name="gameObject"><see cref="GameObject"/> to start checking for a <see cref="NetworkObject"/></param>
/// <param name="networkObjectRemoved">used internally</param>
public static void CheckForNetworkObject(GameObject gameObject, bool networkObjectRemoved = false) public static void CheckForNetworkObject(GameObject gameObject, bool networkObjectRemoved = false)
{ {
// If there are no NetworkBehaviours or no gameObject, then exit early // If there are no NetworkBehaviours or no gameObject, then exit early

View File

@@ -6,6 +6,10 @@ using UnityEditorInternal;
namespace Unity.Netcode.Editor namespace Unity.Netcode.Editor
{ {
/// <summary>
/// This <see cref="CustomEditor"/> handles the translation between the <see cref="NetworkConfig"/> and
/// the <see cref="NetworkManager"/> properties.
/// </summary>
[CustomEditor(typeof(NetworkManager), true)] [CustomEditor(typeof(NetworkManager), true)]
[CanEditMultipleObjects] [CanEditMultipleObjects]
public class NetworkManagerEditor : UnityEditor.Editor public class NetworkManagerEditor : UnityEditor.Editor
@@ -200,6 +204,7 @@ namespace Unity.Netcode.Editor
m_NetworkPrefabsList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "NetworkPrefabs"); m_NetworkPrefabsList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "NetworkPrefabs");
} }
/// <inheritdoc/>
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
Initialize(); Initialize();

View File

@@ -4,6 +4,9 @@ using UnityEditor;
namespace Unity.Netcode.Editor namespace Unity.Netcode.Editor
{ {
/// <summary>
/// The <see cref="CustomEditor"/> for <see cref="NetworkObject"/>
/// </summary>
[CustomEditor(typeof(NetworkObject), true)] [CustomEditor(typeof(NetworkObject), true)]
[CanEditMultipleObjects] [CanEditMultipleObjects]
public class NetworkObjectEditor : UnityEditor.Editor public class NetworkObjectEditor : UnityEditor.Editor
@@ -23,6 +26,7 @@ namespace Unity.Netcode.Editor
m_NetworkObject = (NetworkObject)target; m_NetworkObject = (NetworkObject)target;
} }
/// <inheritdoc/>
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
Initialize(); Initialize();

View File

@@ -4,6 +4,9 @@ using Unity.Netcode.Components;
namespace Unity.Netcode.Editor namespace Unity.Netcode.Editor
{ {
/// <summary>
/// The <see cref="CustomEditor"/> for <see cref="NetworkTransform"/>
/// </summary>
[CustomEditor(typeof(NetworkTransform), true)] [CustomEditor(typeof(NetworkTransform), true)]
public class NetworkTransformEditor : UnityEditor.Editor public class NetworkTransformEditor : UnityEditor.Editor
{ {
@@ -28,6 +31,7 @@ namespace Unity.Netcode.Editor
private static GUIContent s_RotationLabel = EditorGUIUtility.TrTextContent("Rotation"); private static GUIContent s_RotationLabel = EditorGUIUtility.TrTextContent("Rotation");
private static GUIContent s_ScaleLabel = EditorGUIUtility.TrTextContent("Scale"); private static GUIContent s_ScaleLabel = EditorGUIUtility.TrTextContent("Scale");
/// <inheritdoc/>
public void OnEnable() public void OnEnable()
{ {
m_SyncPositionXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionX)); m_SyncPositionXProperty = serializedObject.FindProperty(nameof(NetworkTransform.SyncPositionX));
@@ -46,6 +50,7 @@ namespace Unity.Netcode.Editor
m_InterpolateProperty = serializedObject.FindProperty(nameof(NetworkTransform.Interpolate)); m_InterpolateProperty = serializedObject.FindProperty(nameof(NetworkTransform.Interpolate));
} }
/// <inheritdoc/>
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
EditorGUILayout.LabelField("Syncing", EditorStyles.boldLabel); EditorGUILayout.LabelField("Syncing", EditorStyles.boldLabel);

View File

@@ -150,8 +150,16 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public bool EnableNetworkLogs = true; public bool EnableNetworkLogs = true;
/// <summary>
/// The number of RTT samples that is kept as an average for calculations
/// </summary>
public const int RttAverageSamples = 5; // number of RTT to keep an average of (plus one) public const int RttAverageSamples = 5; // number of RTT to keep an average of (plus one)
/// <summary>
/// The number of slots used for RTT calculations. This is the maximum amount of in-flight messages
/// </summary>
public const int RttWindowSize = 64; // number of slots to use for RTT computations (max number of in-flight packets) public const int RttWindowSize = 64; // number of slots to use for RTT computations (max number of in-flight packets)
/// <summary> /// <summary>
/// Returns a base64 encoded version of the configuration /// Returns a base64 encoded version of the configuration
/// </summary> /// </summary>

View File

@@ -470,6 +470,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Gets called when the parent NetworkObject of this NetworkBehaviour's NetworkObject has changed /// Gets called when the parent NetworkObject of this NetworkBehaviour's NetworkObject has changed
/// </summary> /// </summary>
/// <param name="parentNetworkObject">the new <see cref="NetworkObject"/> parent</param>
public virtual void OnNetworkObjectParentChanged(NetworkObject parentNetworkObject) { } public virtual void OnNetworkObjectParentChanged(NetworkObject parentNetworkObject) { }
private bool m_VarInit = false; private bool m_VarInit = false;
@@ -751,6 +752,11 @@ namespace Unity.Netcode
return NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(networkId, out NetworkObject networkObject) ? networkObject : null; return NetworkManager.SpawnManager.SpawnedObjects.TryGetValue(networkId, out NetworkObject networkObject) ? networkObject : null;
} }
/// <summary>
/// Invoked when the <see cref="GameObject"/> the <see cref="NetworkBehaviour"/> is attached to.
/// NOTE: If you override this, you will want to always invoke this base class version of this
/// <see cref="OnDestroy"/> method!!
/// </summary>
public virtual void OnDestroy() public virtual void OnDestroy()
{ {
// this seems odd to do here, but in fact especially in tests we can find ourselves // this seems odd to do here, but in fact especially in tests we can find ourselves

View File

@@ -3,6 +3,9 @@ using Unity.Profiling;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// An helper class that helps NetworkManager update NetworkBehaviours and replicate them down to connected clients.
/// </summary>
public class NetworkBehaviourUpdater public class NetworkBehaviourUpdater
{ {
private HashSet<NetworkObject> m_Touched = new HashSet<NetworkObject>(); private HashSet<NetworkObject> m_Touched = new HashSet<NetworkObject>();

View File

@@ -62,6 +62,9 @@ namespace Unity.Netcode
internal Dictionary<ulong, ConnectionApprovalResponse> ClientsToApprove = new Dictionary<ulong, ConnectionApprovalResponse>(); internal Dictionary<ulong, ConnectionApprovalResponse> ClientsToApprove = new Dictionary<ulong, ConnectionApprovalResponse>();
/// <summary>
/// The <see cref="NetworkPrefabHandler"/> instance created after starting the <see cref="NetworkManager"/>
/// </summary>
public NetworkPrefabHandler PrefabHandler public NetworkPrefabHandler PrefabHandler
{ {
get get
@@ -197,12 +200,25 @@ namespace Unity.Netcode
return gameObject; return gameObject;
} }
/// <summary>
/// Accessor for the <see cref="NetworkTimeSystem"/> of the NetworkManager.
/// Prefer the use of the LocalTime and ServerTime properties
/// </summary>
public NetworkTimeSystem NetworkTimeSystem { get; private set; } public NetworkTimeSystem NetworkTimeSystem { get; private set; }
/// <summary>
/// Accessor for the <see cref="NetworkTickSystem"/> of the NetworkManager.
/// </summary>
public NetworkTickSystem NetworkTickSystem { get; private set; } public NetworkTickSystem NetworkTickSystem { get; private set; }
/// <summary>
/// The local <see cref="NetworkTime"/>
/// </summary>
public NetworkTime LocalTime => NetworkTickSystem?.LocalTime ?? default; public NetworkTime LocalTime => NetworkTickSystem?.LocalTime ?? default;
/// <summary>
/// The <see cref="NetworkTime"/> on the server
/// </summary>
public NetworkTime ServerTime => NetworkTickSystem?.ServerTime ?? default; public NetworkTime ServerTime => NetworkTickSystem?.ServerTime ?? default;
/// <summary> /// <summary>
@@ -229,10 +245,19 @@ namespace Unity.Netcode
internal IDeferredMessageManager DeferredMessageManager { get; private set; } internal IDeferredMessageManager DeferredMessageManager { get; private set; }
/// <summary>
/// Gets the CustomMessagingManager for this NetworkManager
/// </summary>
public CustomMessagingManager CustomMessagingManager { get; private set; } public CustomMessagingManager CustomMessagingManager { get; private set; }
/// <summary>
/// The <see cref="NetworkSceneManager"/> instance created after starting the <see cref="NetworkManager"/>
/// </summary>
public NetworkSceneManager SceneManager { get; private set; } public NetworkSceneManager SceneManager { get; private set; }
/// <summary>
/// The client id used to represent the server
/// </summary>
public const ulong ServerClientId = 0; public const ulong ServerClientId = 0;
/// <summary> /// <summary>
@@ -341,7 +366,9 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public bool IsConnectedClient { get; internal set; } public bool IsConnectedClient { get; internal set; }
/// <summary>
/// Can be used to determine if the <see cref="NetworkManager"/> is currently shutting itself down
/// </summary>
public bool ShutdownInProgress { get { return m_ShuttingDown; } } public bool ShutdownInProgress { get { return m_ShuttingDown; } }
/// <summary> /// <summary>
@@ -374,30 +401,46 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Connection Approval Response /// Connection Approval Response
/// </summary> /// </summary>
/// <param name="Approved">Whether or not the client was approved</param>
/// <param name="CreatePlayerObject">If true, a player object will be created. Otherwise the client will have no object.</param>
/// <param name="PlayerPrefabHash">The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.</param>
/// <param name="Position">The position to spawn the client at. If null, the prefab position is used.</param>
/// <param name="Rotation">The rotation to spawn the client with. If null, the prefab position is used.</param>
/// <param name="Pending">If the Approval decision cannot be made immediately, the client code can set Pending to true, keep a reference to the ConnectionApprovalResponse object and write to it later. Client code must exercise care to setting all the members to the value it wants before marking Pending to false, to indicate completion. If the field is set as Pending = true, we'll monitor the object until it gets set to not pending anymore and use the parameters then.</param>
public class ConnectionApprovalResponse public class ConnectionApprovalResponse
{ {
/// <summary>
/// Whether or not the client was approved
/// </summary>
public bool Approved; public bool Approved;
/// <summary>
/// If true, a player object will be created. Otherwise the client will have no object.
/// </summary>
public bool CreatePlayerObject; public bool CreatePlayerObject;
/// <summary>
/// The prefabHash to use for the client. If createPlayerObject is false, this is ignored. If playerPrefabHash is null, the default player prefab is used.
/// </summary>
public uint? PlayerPrefabHash; public uint? PlayerPrefabHash;
/// <summary>
/// The position to spawn the client at. If null, the prefab position is used.
/// </summary>
public Vector3? Position; public Vector3? Position;
/// <summary>
/// The rotation to spawn the client with. If null, the prefab position is used.
/// </summary>
public Quaternion? Rotation; public Quaternion? Rotation;
/// <summary>
/// If the Approval decision cannot be made immediately, the client code can set Pending to true, keep a reference to the ConnectionApprovalResponse object and write to it later. Client code must exercise care to setting all the members to the value it wants before marking Pending to false, to indicate completion. If the field is set as Pending = true, we'll monitor the object until it gets set to not pending anymore and use the parameters then.
/// </summary>
public bool Pending; public bool Pending;
} }
/// <summary> /// <summary>
/// Connection Approval Request /// Connection Approval Request
/// </summary> /// </summary>
/// <param name="Payload">The connection data payload</param>
/// <param name="ClientNetworkId">The Network Id of the client we are about to handle</param>
public struct ConnectionApprovalRequest public struct ConnectionApprovalRequest
{ {
/// <summary>
/// The connection data payload
/// </summary>
public byte[] Payload; public byte[] Payload;
/// <summary>
/// The Network Id of the client we are about to handle
/// </summary>
public ulong ClientNetworkId; public ulong ClientNetworkId;
} }
@@ -961,6 +1004,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Starts a server /// Starts a server
/// </summary> /// </summary>
/// <returns>(<see cref="true"/>/<see cref="false"/>) returns true if <see cref="NetworkManager"/> started in server mode successfully.</returns>
public bool StartServer() public bool StartServer()
{ {
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
@@ -1000,6 +1044,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Starts a client /// Starts a client
/// </summary> /// </summary>
/// <returns>(<see cref="true"/>/<see cref="false"/>) returns true if <see cref="NetworkManager"/> started in client mode successfully.</returns>
public bool StartClient() public bool StartClient()
{ {
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
@@ -1033,6 +1078,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Starts a Host /// Starts a Host
/// </summary> /// </summary>
/// <returns>(<see cref="true"/>/<see cref="false"/>) returns true if <see cref="NetworkManager"/> started in host mode successfully.</returns>
public bool StartHost() public bool StartHost()
{ {
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
@@ -1144,6 +1190,9 @@ namespace Unity.Netcode
return true; return true;
} }
/// <summary>
/// Set this NetworkManager instance as the static NetworkManager singleton
/// </summary>
public void SetSingleton() public void SetSingleton()
{ {
Singleton = this; Singleton = this;
@@ -1405,7 +1454,7 @@ namespace Unity.Netcode
ClearClients(); ClearClients();
} }
// INetworkUpdateSystem /// <inheritdoc />
public void NetworkUpdate(NetworkUpdateStage updateStage) public void NetworkUpdate(NetworkUpdateStage updateStage)
{ {
switch (updateStage) switch (updateStage)

View File

@@ -541,16 +541,34 @@ namespace Unity.Netcode
m_LatestParent = latestParent; m_LatestParent = latestParent;
} }
/// <summary>
/// Set the parent of the NetworkObject transform.
/// </summary>
/// <param name="parent">The new parent for this NetworkObject transform will be the child of.</param>
/// <param name="worldPositionStays">If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.</param>
/// <returns>Whether or not reparenting was successful.</returns>
public bool TrySetParent(Transform parent, bool worldPositionStays = true) public bool TrySetParent(Transform parent, bool worldPositionStays = true)
{ {
return TrySetParent(parent.GetComponent<NetworkObject>(), worldPositionStays); return TrySetParent(parent.GetComponent<NetworkObject>(), worldPositionStays);
} }
/// <summary>
/// Set the parent of the NetworkObject transform.
/// </summary>
/// <param name="parent">The new parent for this NetworkObject transform will be the child of.</param>
/// <param name="worldPositionStays">If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.</param>
/// <returns>Whether or not reparenting was successful.</returns>
public bool TrySetParent(GameObject parent, bool worldPositionStays = true) public bool TrySetParent(GameObject parent, bool worldPositionStays = true)
{ {
return TrySetParent(parent.GetComponent<NetworkObject>(), worldPositionStays); return TrySetParent(parent.GetComponent<NetworkObject>(), worldPositionStays);
} }
/// <summary>
/// Set the parent of the NetworkObject transform.
/// </summary>
/// <param name="parent">The new parent for this NetworkObject transform will be the child of.</param>
/// <param name="worldPositionStays">If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.</param>
/// <returns>Whether or not reparenting was successful.</returns>
public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true) public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true)
{ {
if (!AutoObjectParentSync) if (!AutoObjectParentSync)
@@ -813,8 +831,8 @@ namespace Unity.Netcode
// if and when we have different systems for where it is expected that orphans survive across ticks, // if and when we have different systems for where it is expected that orphans survive across ticks,
// then this warning will remind us that we need to revamp the system because then we can no longer simply // then this warning will remind us that we need to revamp the system because then we can no longer simply
// spawn the orphan without its parent (at least, not when its transform is set to local coords mode) // spawn the orphan without its parent (at least, not when its transform is set to local coords mode)
// - because then youll have children popping at the wrong location not having their parents global position to root them // - because then you'll have children popping at the wrong location not having their parent's global position to root them
// - and then theyll pop to the correct location after they get the parent, and that would be not good // - and then they'll pop to the correct location after they get the parent, and that would be not good
internal static void VerifyParentingStatus() internal static void VerifyParentingStatus()
{ {
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)

View File

@@ -7,25 +7,55 @@ using UnityEngine.PlayerLoop;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary> /// <summary>
/// Defines the required interface of a network update system being executed by the network update loop. /// Defines the required interface of a network update system being executed by the <see cref="NetworkUpdateLoop"/>.
/// </summary> /// </summary>
public interface INetworkUpdateSystem public interface INetworkUpdateSystem
{ {
/// <summary>
/// The update method that is being executed in the context of related <see cref="NetworkUpdateStage"/>.
/// </summary>
/// <param name="updateStage">The <see cref="NetworkUpdateStage"/> that is being executed.</param>
void NetworkUpdate(NetworkUpdateStage updateStage); void NetworkUpdate(NetworkUpdateStage updateStage);
} }
/// <summary> /// <summary>
/// Defines network update stages being executed by the network update loop. /// Defines network update stages being executed by the network update loop.
/// See for more details on update stages:
/// https://docs.unity3d.com/ScriptReference/PlayerLoop.Initialization.html
/// </summary> /// </summary>
public enum NetworkUpdateStage : byte public enum NetworkUpdateStage : byte
{ {
Unset = 0, // Default /// <summary>
/// Default value
/// </summary>
Unset = 0,
/// <summary>
/// Very first initialization update
/// </summary>
Initialization = 1, Initialization = 1,
/// <summary>
/// Invoked before Fixed update
/// </summary>
EarlyUpdate = 2, EarlyUpdate = 2,
/// <summary>
/// Fixed Update (i.e. state machine, physics, animations, etc)
/// </summary>
FixedUpdate = 3, FixedUpdate = 3,
/// <summary>
/// Updated before the Monobehaviour.Update for all components is invoked
/// </summary>
PreUpdate = 4, PreUpdate = 4,
/// <summary>
/// Updated when the Monobehaviour.Update for all components is invoked
/// </summary>
Update = 5, Update = 5,
/// <summary>
/// Updated before the Monobehaviour.LateUpdate for all components is invoked
/// </summary>
PreLateUpdate = 6, PreLateUpdate = 6,
/// <summary>
/// Updated after the Monobehaviour.LateUpdate for all components is invoked
/// </summary>
PostLateUpdate = 7 PostLateUpdate = 7
} }
@@ -53,6 +83,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Registers a network update system to be executed in all network update stages. /// Registers a network update system to be executed in all network update stages.
/// </summary> /// </summary>
/// <param name="updateSystem">The <see cref="INetworkUpdateSystem"/> implementation to register for all network updates</param>
public static void RegisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem) public static void RegisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem)
{ {
foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage))) foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
@@ -64,6 +95,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Registers a network update system to be executed in a specific network update stage. /// Registers a network update system to be executed in a specific network update stage.
/// </summary> /// </summary>
/// <param name="updateSystem">The <see cref="INetworkUpdateSystem"/> implementation to register for all network updates</param>
/// <param name="updateStage">The <see cref="NetworkUpdateStage"/> being registered for the <see cref="INetworkUpdateSystem"/> implementation</param>
public static void RegisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update) public static void RegisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update)
{ {
var sysSet = s_UpdateSystem_Sets[updateStage]; var sysSet = s_UpdateSystem_Sets[updateStage];
@@ -94,6 +127,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Unregisters a network update system from all network update stages. /// Unregisters a network update system from all network update stages.
/// </summary> /// </summary>
/// <param name="updateSystem">The <see cref="INetworkUpdateSystem"/> implementation to deregister from all network updates</param>
public static void UnregisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem) public static void UnregisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem)
{ {
foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage))) foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
@@ -105,6 +139,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Unregisters a network update system from a specific network update stage. /// Unregisters a network update system from a specific network update stage.
/// </summary> /// </summary>
/// <param name="updateSystem">The <see cref="INetworkUpdateSystem"/> implementation to deregister from all network updates</param>
/// <param name="updateStage">The <see cref="NetworkUpdateStage"/> to be deregistered from the <see cref="INetworkUpdateSystem"/> implementation</param>
public static void UnregisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update) public static void UnregisterNetworkUpdate(this INetworkUpdateSystem updateSystem, NetworkUpdateStage updateStage = NetworkUpdateStage.Update)
{ {
var sysSet = s_UpdateSystem_Sets[updateStage]; var sysSet = s_UpdateSystem_Sets[updateStage];

View File

@@ -7,8 +7,18 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public class InvalidParentException : Exception public class InvalidParentException : Exception
{ {
/// <summary>
/// Constructor for <see cref="InvalidParentException"/>
/// </summary>
public InvalidParentException() { } public InvalidParentException() { }
/// <inheritdoc/>
/// <param name="message"></param>
public InvalidParentException(string message) : base(message) { } public InvalidParentException(string message) : base(message) { }
/// <inheritdoc/>
/// <param name="message"></param>
/// <param name="innerException"></param>
public InvalidParentException(string message, Exception innerException) : base(message, innerException) { } public InvalidParentException(string message, Exception innerException) : base(message, innerException) { }
} }
} }

View File

@@ -26,8 +26,15 @@ namespace Unity.Netcode
public SpawnStateException(string message, Exception inner) : base(message, inner) { } public SpawnStateException(string message, Exception inner) : base(message, inner) { }
} }
/// <summary>
/// Exception thrown when a specified network channel is invalid
/// </summary>
public class InvalidChannelException : Exception public class InvalidChannelException : Exception
{ {
/// <summary>
/// Constructs an InvalidChannelException with a message
/// </summary>
/// <param name="message">the message</param>
public InvalidChannelException(string message) : base(message) { } public InvalidChannelException(string message) : base(message) { }
} }
} }

View File

@@ -14,8 +14,23 @@ namespace Unity.Netcode
public static LogLevel CurrentLogLevel => NetworkManager.Singleton == null ? LogLevel.Normal : NetworkManager.Singleton.LogLevel; public static LogLevel CurrentLogLevel => NetworkManager.Singleton == null ? LogLevel.Normal : NetworkManager.Singleton.LogLevel;
// internal logging // internal logging
/// <summary>
/// Locally logs a info log with Netcode prefixing.
/// </summary>
/// <param name="message">The message to log</param>
public static void LogInfo(string message) => Debug.Log($"[Netcode] {message}"); public static void LogInfo(string message) => Debug.Log($"[Netcode] {message}");
/// <summary>
/// Locally logs a warning log with Netcode prefixing.
/// </summary>
/// <param name="message">The message to log</param>
public static void LogWarning(string message) => Debug.LogWarning($"[Netcode] {message}"); public static void LogWarning(string message) => Debug.LogWarning($"[Netcode] {message}");
/// <summary>
/// Locally logs a error log with Netcode prefixing.
/// </summary>
/// <param name="message">The message to log</param>
public static void LogError(string message) => Debug.LogError($"[Netcode] {message}"); public static void LogError(string message) => Debug.LogError($"[Netcode] {message}");
/// <summary> /// <summary>

View File

@@ -193,6 +193,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Sends a named message to all clients /// Sends a named message to all clients
/// </summary> /// </summary>
/// <param name="messageName">The message name to send</param>
/// <param name="messageStream">The message stream containing the data</param> /// <param name="messageStream">The message stream containing the data</param>
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param> /// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
public void SendNamedMessageToAll(string messageName, FastBufferWriter messageStream, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced) public void SendNamedMessageToAll(string messageName, FastBufferWriter messageStream, NetworkDelivery networkDelivery = NetworkDelivery.ReliableSequenced)

View File

@@ -3,21 +3,52 @@ using Unity.Collections;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Server-Side RPC
/// Place holder. <see cref="ServerRpcParams"/>
/// Note: Clients always send to one destination when sending RPCs to the server
/// so this structure is a place holder
/// </summary>
public struct ServerRpcSendParams public struct ServerRpcSendParams
{ {
} }
/// <summary>
/// The receive parameters for server-side remote procedure calls
/// </summary>
public struct ServerRpcReceiveParams public struct ServerRpcReceiveParams
{ {
/// <summary>
/// Server-Side RPC
/// The client identifier of the sender
/// </summary>
public ulong SenderClientId; public ulong SenderClientId;
} }
/// <summary>
/// Server-Side RPC
/// Can be used with any sever-side remote procedure call
/// Note: typically this is use primarily for the <see cref="ServerRpcReceiveParams"/>
/// </summary>
public struct ServerRpcParams public struct ServerRpcParams
{ {
/// <summary>
/// The server RPC send parameters (currently a place holder)
/// </summary>
public ServerRpcSendParams Send; public ServerRpcSendParams Send;
/// <summary>
/// The client RPC receive parameters provides you with the sender's identifier
/// </summary>
public ServerRpcReceiveParams Receive; public ServerRpcReceiveParams Receive;
} }
/// <summary>
/// Client-Side RPC
/// The send parameters, when sending client RPCs, provides you wil the ability to
/// target specific clients as a managed or unmanaged list:
/// <see cref="TargetClientIds"/> and <see cref="TargetClientIdsNativeArray"/>
/// </summary>
public struct ClientRpcSendParams public struct ClientRpcSendParams
{ {
/// <summary> /// <summary>
@@ -34,13 +65,32 @@ namespace Unity.Netcode
public NativeArray<ulong>? TargetClientIdsNativeArray; public NativeArray<ulong>? TargetClientIdsNativeArray;
} }
/// <summary>
/// Client-Side RPC
/// Place holder. <see cref="ServerRpcParams"/>
/// Note: Server will always be the sender, so this structure is a place holder
/// </summary>
public struct ClientRpcReceiveParams public struct ClientRpcReceiveParams
{ {
} }
/// <summary>
/// Client-Side RPC
/// Can be used with any client-side remote procedure call
/// Note: Typically this is used primarily for sending to a specific list
/// of clients as opposed to the default (all).
/// <see cref="ClientRpcSendParams"/>
/// </summary>
public struct ClientRpcParams public struct ClientRpcParams
{ {
/// <summary>
/// The client RPC send parameters provides you with the ability to send to a specific list of clients
/// </summary>
public ClientRpcSendParams Send; public ClientRpcSendParams Send;
/// <summary>
/// The client RPC receive parameters (currently a place holder)
/// </summary>
public ClientRpcReceiveParams Receive; public ClientRpcReceiveParams Receive;
} }

View File

@@ -25,8 +25,15 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public event OnListChangedDelegate OnListChanged; public event OnListChangedDelegate OnListChanged;
/// <summary>
/// Constructor method for <see cref="NetworkList"/>
/// </summary>
public NetworkList() { } public NetworkList() { }
/// <inheritdoc/>
/// <param name="values"></param>
/// <param name="readPerm"></param>
/// <param name="writePerm"></param>
public NetworkList(IEnumerable<T> values = default, public NetworkList(IEnumerable<T> values = default,
NetworkVariableReadPermission readPerm = DefaultReadPerm, NetworkVariableReadPermission readPerm = DefaultReadPerm,
NetworkVariableWritePermission writePerm = DefaultWritePerm) NetworkVariableWritePermission writePerm = DefaultWritePerm)
@@ -448,6 +455,9 @@ namespace Unity.Netcode
OnListChanged?.Invoke(listEvent); OnListChanged?.Invoke(listEvent);
} }
/// <summary>
/// This is actually unused left-over from a previous interface
/// </summary>
public int LastModifiedTick public int LastModifiedTick
{ {
get get
@@ -457,6 +467,11 @@ namespace Unity.Netcode
} }
} }
/// <summary>
/// Overridden <see cref="IDisposable"/> implementation.
/// CAUTION: If you derive from this class and override the <see cref="Dispose"/> method,
/// you **must** always invoke the base.Dispose() method!
/// </summary>
public override void Dispose() public override void Dispose()
{ {
m_List.Dispose(); m_List.Dispose();

View File

@@ -8,6 +8,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// A variable that can be synchronized over the network. /// A variable that can be synchronized over the network.
/// </summary> /// </summary>
/// <typeparam name="T">the unmanaged type for <see cref="NetworkVariable{T}"/> </typeparam>
[Serializable] [Serializable]
public class NetworkVariable<T> : NetworkVariableBase where T : unmanaged public class NetworkVariable<T> : NetworkVariableBase where T : unmanaged
{ {
@@ -22,7 +23,12 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public OnValueChangedDelegate OnValueChanged; public OnValueChangedDelegate OnValueChanged;
/// <summary>
/// Constructor for <see cref="NetworkVariable{T}"/>
/// </summary>
/// <param name="value">initial value set that is of type T</param>
/// <param name="readPerm">the <see cref="NetworkVariableReadPermission"/> for this <see cref="NetworkVariable{T}"/></param>
/// <param name="writePerm">the <see cref="NetworkVariableWritePermission"/> for this <see cref="NetworkVariable{T}"/></param>
public NetworkVariable(T value = default, public NetworkVariable(T value = default,
NetworkVariableReadPermission readPerm = DefaultReadPerm, NetworkVariableReadPermission readPerm = DefaultReadPerm,
NetworkVariableWritePermission writePerm = DefaultWritePerm) NetworkVariableWritePermission writePerm = DefaultWritePerm)
@@ -31,6 +37,9 @@ namespace Unity.Netcode
m_InternalValue = value; m_InternalValue = value;
} }
/// <summary>
/// The internal value of the NetworkVariable
/// </summary>
[SerializeField] [SerializeField]
private protected T m_InternalValue; private protected T m_InternalValue;
@@ -58,7 +67,7 @@ namespace Unity.Netcode
} }
// Compares two values of the same unmanaged type by underlying memory // Compares two values of the same unmanaged type by underlying memory
// Ignoring any overriden value checks // Ignoring any overridden value checks
// Size is fixed // Size is fixed
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe bool ValueEquals(ref T a, ref T b) private static unsafe bool ValueEquals(ref T a, ref T b)
@@ -71,7 +80,11 @@ namespace Unity.Netcode
return UnsafeUtility.MemCmp(aptr, bptr, sizeof(T)) == 0; return UnsafeUtility.MemCmp(aptr, bptr, sizeof(T)) == 0;
} }
/// <summary>
/// Sets the <see cref="Value"/>, marks the <see cref="NetworkVariable{T}"/> dirty, and invokes the <see cref="OnValueChanged"/> callback
/// if there are subscribers to that event.
/// </summary>
/// <param name="value">the new value of type `T` to be set/></param>
private protected void Set(T value) private protected void Set(T value)
{ {
m_IsDirty = true; m_IsDirty = true;

View File

@@ -12,16 +12,36 @@ namespace Unity.Netcode
/// </summary> /// </summary>
internal const NetworkDelivery Delivery = NetworkDelivery.ReliableFragmentedSequenced; internal const NetworkDelivery Delivery = NetworkDelivery.ReliableFragmentedSequenced;
/// <summary>
/// Maintains a link to the associated NetworkBehaviour
/// </summary>
private protected NetworkBehaviour m_NetworkBehaviour; private protected NetworkBehaviour m_NetworkBehaviour;
/// <summary>
/// Initializes the NetworkVariable
/// </summary>
/// <param name="networkBehaviour">The NetworkBehaviour the NetworkVariable belongs to</param>
public void Initialize(NetworkBehaviour networkBehaviour) public void Initialize(NetworkBehaviour networkBehaviour)
{ {
m_NetworkBehaviour = networkBehaviour; m_NetworkBehaviour = networkBehaviour;
} }
/// <summary>
/// The default read permissions
/// </summary>
public const NetworkVariableReadPermission DefaultReadPerm = NetworkVariableReadPermission.Everyone; public const NetworkVariableReadPermission DefaultReadPerm = NetworkVariableReadPermission.Everyone;
/// <summary>
/// The default write permissions
/// </summary>
public const NetworkVariableWritePermission DefaultWritePerm = NetworkVariableWritePermission.Server; public const NetworkVariableWritePermission DefaultWritePerm = NetworkVariableWritePermission.Server;
/// <summary>
/// The default constructor for <see cref="NetworkVariableBase"/> that can be used to create a
/// custom NetworkVariable.
/// </summary>
/// <param name="readPerm">the <see cref="NetworkVariableReadPermission"/> access settings</param>
/// <param name="writePerm">the <see cref="NetworkVariableWritePermission"/> access settings</param>
protected NetworkVariableBase( protected NetworkVariableBase(
NetworkVariableReadPermission readPerm = DefaultReadPerm, NetworkVariableReadPermission readPerm = DefaultReadPerm,
NetworkVariableWritePermission writePerm = DefaultWritePerm) NetworkVariableWritePermission writePerm = DefaultWritePerm)
@@ -30,6 +50,10 @@ namespace Unity.Netcode
WritePerm = writePerm; WritePerm = writePerm;
} }
/// <summary>
/// The <see cref="m_IsDirty"/> property is used to determine if the
/// value of the `NetworkVariable` has changed.
/// </summary>
private protected bool m_IsDirty; private protected bool m_IsDirty;
/// <summary> /// <summary>
@@ -43,11 +67,15 @@ namespace Unity.Netcode
/// </summary> /// </summary>
public readonly NetworkVariableReadPermission ReadPerm; public readonly NetworkVariableReadPermission ReadPerm;
/// <summary>
/// The write permission for this var
/// </summary>
public readonly NetworkVariableWritePermission WritePerm; public readonly NetworkVariableWritePermission WritePerm;
/// <summary> /// <summary>
/// Sets whether or not the variable needs to be delta synced /// Sets whether or not the variable needs to be delta synced
/// </summary> /// </summary>
/// <param name="isDirty">Whether or not the var is dirty</param>
public virtual void SetDirty(bool isDirty) public virtual void SetDirty(bool isDirty)
{ {
m_IsDirty = isDirty; m_IsDirty = isDirty;
@@ -70,6 +98,11 @@ namespace Unity.Netcode
return m_IsDirty; return m_IsDirty;
} }
/// <summary>
/// Gets if a specific client has permission to read the var or not
/// </summary>
/// <param name="clientId">The client id</param>
/// <returns>Whether or not the client has permission to read</returns>
public bool CanClientRead(ulong clientId) public bool CanClientRead(ulong clientId)
{ {
switch (ReadPerm) switch (ReadPerm)
@@ -82,6 +115,11 @@ namespace Unity.Netcode
} }
} }
/// <summary>
/// Gets if a specific client has permission to write the var or not
/// </summary>
/// <param name="clientId">The client id</param>
/// <returns>Whether or not the client has permission to write</returns>
public bool CanClientWrite(ulong clientId) public bool CanClientWrite(ulong clientId)
{ {
switch (WritePerm) switch (WritePerm)
@@ -127,6 +165,9 @@ namespace Unity.Netcode
/// <param name="keepDirtyDelta">Whether or not the delta should be kept as dirty or consumed</param> /// <param name="keepDirtyDelta">Whether or not the delta should be kept as dirty or consumed</param>
public abstract void ReadDelta(FastBufferReader reader, bool keepDirtyDelta); public abstract void ReadDelta(FastBufferReader reader, bool keepDirtyDelta);
/// <summary>
/// Virtual <see cref="IDisposable"/> implementation
/// </summary>
public virtual void Dispose() public virtual void Dispose()
{ {
} }

View File

@@ -1,14 +1,32 @@
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// The permission types for reading a var
/// </summary>
public enum NetworkVariableReadPermission public enum NetworkVariableReadPermission
{ {
/// <summary>
/// Everyone can read
/// </summary>
Everyone, Everyone,
/// <summary>
/// Only the owner and the server can read
/// </summary>
Owner, Owner,
} }
/// <summary>
/// The permission types for writing a var
/// </summary>
public enum NetworkVariableWritePermission public enum NetworkVariableWritePermission
{ {
/// <summary>
/// Only the server can write
/// </summary>
Server, Server,
/// <summary>
/// Only the owner can write
/// </summary>
Owner Owner
} }
} }

View File

@@ -120,10 +120,28 @@ namespace Unity.Netcode
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public class UserNetworkVariableSerialization<T> public class UserNetworkVariableSerialization<T>
{ {
/// <summary>
/// The write value delegate handler definition
/// </summary>
/// <param name="writer">The <see cref="FastBufferWriter"/> to write the value of type `T`</param>
/// <param name="value">The value of type `T` to be written</param>
public delegate void WriteValueDelegate(FastBufferWriter writer, in T value); public delegate void WriteValueDelegate(FastBufferWriter writer, in T value);
/// <summary>
/// The read value delegate handler definition
/// </summary>
/// <param name="reader">The <see cref="FastBufferReader"/> to read the value of type `T`</param>
/// <param name="value">The value of type `T` to be read</param>
public delegate void ReadValueDelegate(FastBufferReader reader, out T value); public delegate void ReadValueDelegate(FastBufferReader reader, out T value);
/// <summary>
/// The <see cref="WriteValueDelegate"/> delegate handler declaration
/// </summary>
public static WriteValueDelegate WriteValue; public static WriteValueDelegate WriteValue;
/// <summary>
/// The <see cref="ReadValueDelegate"/> delegate handler declaration
/// </summary>
public static ReadValueDelegate ReadValue; public static ReadValueDelegate ReadValue;
} }
@@ -192,6 +210,7 @@ namespace Unity.Netcode
/// but there's no way to achieve the same thing with a class, this sets up various read/write schemes /// but there's no way to achieve the same thing with a class, this sets up various read/write schemes
/// based on which constraints are met by `T` using reflection, which is done at module load time. /// based on which constraints are met by `T` using reflection, which is done at module load time.
/// </summary> /// </summary>
/// <typeparam name="T">The type the associated NetworkVariable is templated on</typeparam>
[Serializable] [Serializable]
public static class NetworkVariableSerialization<T> where T : unmanaged public static class NetworkVariableSerialization<T> where T : unmanaged
{ {

View File

@@ -935,7 +935,7 @@ namespace Unity.Netcode
/// Unloads an additively loaded scene. If you want to unload a <see cref="LoadSceneMode.Single"/> mode loaded scene load another <see cref="LoadSceneMode.Single"/> scene. /// Unloads an additively loaded scene. If you want to unload a <see cref="LoadSceneMode.Single"/> mode loaded scene load another <see cref="LoadSceneMode.Single"/> scene.
/// When applicable, the <see cref="AsyncOperation"/> is delivered within the <see cref="SceneEvent"/> via the <see cref="OnSceneEvent"/> /// When applicable, the <see cref="AsyncOperation"/> is delivered within the <see cref="SceneEvent"/> via the <see cref="OnSceneEvent"/>
/// </summary> /// </summary>
/// <param name="sceneName">scene name to unload</param> /// <param name="scene"></param>
/// <returns><see cref="SceneEventProgressStatus"/> (<see cref="SceneEventProgressStatus.Started"/> means it was successful)</returns> /// <returns><see cref="SceneEventProgressStatus"/> (<see cref="SceneEventProgressStatus.Started"/> means it was successful)</returns>
public SceneEventProgressStatus UnloadScene(Scene scene) public SceneEventProgressStatus UnloadScene(Scene scene)
{ {
@@ -1134,6 +1134,7 @@ namespace Unity.Netcode
/// When applicable, the <see cref="AsyncOperation"/> is delivered within the <see cref="SceneEvent"/> via <see cref="OnSceneEvent"/> /// When applicable, the <see cref="AsyncOperation"/> is delivered within the <see cref="SceneEvent"/> via <see cref="OnSceneEvent"/>
/// </summary> /// </summary>
/// <param name="sceneName">the name of the scene to be loaded</param> /// <param name="sceneName">the name of the scene to be loaded</param>
/// <param name="loadSceneMode">how the scene will be loaded (single or additive mode)</param>
/// <returns><see cref="SceneEventProgressStatus"/> (<see cref="SceneEventProgressStatus.Started"/> means it was successful)</returns> /// <returns><see cref="SceneEventProgressStatus"/> (<see cref="SceneEventProgressStatus.Started"/> means it was successful)</returns>
public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSceneMode) public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSceneMode)
{ {

View File

@@ -2,6 +2,9 @@ using System.Runtime.CompilerServices;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Utility class to count the number of bytes or bits needed to serialize a value.
/// </summary>
public static class BitCounter public static class BitCounter
{ {
// Since we don't have access to BitOperations.LeadingZeroCount() (which would have been the fastest) // Since we don't have access to BitOperations.LeadingZeroCount() (which would have been the fastest)

View File

@@ -62,80 +62,507 @@ namespace Unity.Netcode
return m_Implementation.GetFastBufferWriter(); return m_Implementation.GetFastBufferWriter();
} }
/// <summary>
/// Read or write a string
/// </summary>
/// <param name="s">The value to read/write</param>
/// <param name="oneByteChars">If true, characters will be limited to one-byte ASCII characters</param>
public void SerializeValue(ref string s, bool oneByteChars = false) => m_Implementation.SerializeValue(ref s, oneByteChars); public void SerializeValue(ref string s, bool oneByteChars = false) => m_Implementation.SerializeValue(ref s, oneByteChars);
/// <summary>
/// Read or write a single byte
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref byte value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref byte value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of primitive values (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an enum value
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of enum values
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a struct value implementing ISerializeByMemcpy
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of struct values implementing ISerializeByMemcpy
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a struct or class value implementing INetworkSerializable
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of struct or class values implementing INetworkSerializable
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => m_Implementation.SerializeValue(ref value); public void SerializeValue<T>(ref T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Vector2 value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Vector2 value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector2 value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Vector2 values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Vector2[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector2[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Vector3 value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Vector3 value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector3 value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Vector3 values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Vector3[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector3[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Vector2Int value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Vector2Int value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector2Int value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Vector2Int values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Vector2Int[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector2Int[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Vector3Int value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Vector3Int value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector3Int value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Vector3Int values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Vector3Int[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector3Int[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Vector4 value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Vector4 value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector4 value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Vector4 values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Vector4[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Vector4[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Quaternion value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Quaternion value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Quaternion value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Quaternion values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Quaternion[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Quaternion[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Color value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Color value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Color value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Color values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Color[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Color[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Color32 value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Color32 value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Color32 value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Color32 values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Color32[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Color32[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Ray value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Ray value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Ray value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Ray values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Ray[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Ray[] value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a Ray2D value
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValue(ref Ray2D value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Ray2D value) => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write an array of Ray2D values
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValue(ref Ray2D[] value) => m_Implementation.SerializeValue(ref value); public void SerializeValue(ref Ray2D[] value) => m_Implementation.SerializeValue(ref value);
// There are many FixedString types, but all of them share the interfaces INativeList<bool> and IUTF8Bytes. // There are many FixedString types, but all of them share the interfaces INativeList<bool> and IUTF8Bytes.
// INativeList<bool> provides the Length property // INativeList<bool> provides the Length property
// IUTF8Bytes provides GetUnsafePtr() // IUTF8Bytes provides GetUnsafePtr()
// Those two are necessary to serialize FixedStrings efficiently // Those two are necessary to serialize FixedStrings efficiently
// - otherwise we'd just be memcpying the whole thing even if // - otherwise we'd just be memcpy'ing the whole thing even if
// most of it isn't used. // most of it isn't used.
/// <summary>
/// Read or write a FixedString value
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of FixedStrings</param>
public void SerializeValue<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default) public void SerializeValue<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes => m_Implementation.SerializeValue(ref value); where T : unmanaged, INativeList<byte>, IUTF8Bytes => m_Implementation.SerializeValue(ref value);
/// <summary>
/// Read or write a NetworkSerializable value.
/// SerializeValue() is the preferred method to do this - this is provided for backward compatibility only.
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The values to read/write</param>
public void SerializeNetworkSerializable<T>(ref T value) where T : INetworkSerializable, new() => m_Implementation.SerializeNetworkSerializable(ref value); public void SerializeNetworkSerializable<T>(ref T value) where T : INetworkSerializable, new() => m_Implementation.SerializeNetworkSerializable(ref value);
/// <summary>
/// Performs an advance check to ensure space is available to read/write one or more values.
/// This provides a performance benefit for serializing multiple values using the
/// SerializeValuePreChecked methods. But note that the benefit is small and only likely to be
/// noticeable if serializing a very large number of items.
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
public bool PreCheck(int amount) public bool PreCheck(int amount)
{ {
return m_Implementation.PreCheck(amount); return m_Implementation.PreCheck(amount);
} }
/// <summary>
/// Serialize a string, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="s">The value to read/write</param>
/// <param name="oneByteChars">If true, characters will be limited to one-byte ASCII characters</param>
public void SerializeValuePreChecked(ref string s, bool oneByteChars = false) => m_Implementation.SerializeValuePreChecked(ref s, oneByteChars); public void SerializeValuePreChecked(ref string s, bool oneByteChars = false) => m_Implementation.SerializeValuePreChecked(ref s, oneByteChars);
/// <summary>
/// Serialize a byte, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref byte value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref byte value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a primitive, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize an array of primitives, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable types in an array</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of primitives</param>
public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize an enum, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of enums</param>
public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize an array of enums, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable types in an array</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of enums</param>
public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a struct, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of structs</param>
public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize an array of structs, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable types in an array</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution of structs</param>
public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector2, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector2 value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector2 value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector2 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValuePreChecked(ref Vector2[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector2[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector3, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector3 value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector3 value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector3 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValuePreChecked(ref Vector3[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector3[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector2Int, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector2Int value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector2Int value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector2Int array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
public void SerializeValuePreChecked(ref Vector2Int[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector2Int[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector3Int, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector3Int value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector3Int value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector3Int array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector3Int[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector3Int[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector4, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector4 value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector4 value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Vector4Array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Vector4[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Vector4[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Quaternion, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Quaternion value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Quaternion value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Quaternion array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Quaternion[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Quaternion[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Color, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Color value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Color value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Color array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Color[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Color[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Color32, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Color32 value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Color32 value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Color32 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Color32[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Color32[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Ray, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Ray value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Ray value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Ray array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Ray[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Ray[] value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Ray2D, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Ray2D value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Ray2D value) => m_Implementation.SerializeValuePreChecked(ref value);
/// <summary>
/// Serialize a Ray2D array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
public void SerializeValuePreChecked(ref Ray2D[] value) => m_Implementation.SerializeValuePreChecked(ref value); public void SerializeValuePreChecked(ref Ray2D[] value) => m_Implementation.SerializeValuePreChecked(ref value);
// There are many FixedString types, but all of them share the interfaces INativeList<bool> and IUTF8Bytes. // There are many FixedString types, but all of them share the interfaces INativeList<bool> and IUTF8Bytes.
@@ -144,6 +571,16 @@ namespace Unity.Netcode
// Those two are necessary to serialize FixedStrings efficiently // Those two are necessary to serialize FixedStrings efficiently
// - otherwise we'd just be memcpying the whole thing even if // - otherwise we'd just be memcpying the whole thing even if
// most of it isn't used. // most of it isn't used.
/// <summary>
/// Serialize a FixedString, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The network serializable type</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution for fixed strings</param>
public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default) public void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes => m_Implementation.SerializeValuePreChecked(ref value); where T : unmanaged, INativeList<byte>, IUTF8Bytes => m_Implementation.SerializeValuePreChecked(ref value);
} }

View File

@@ -6,6 +6,7 @@ namespace Unity.Netcode
{ {
/// <summary> /// <summary>
/// Utility class for packing values in serialization. /// Utility class for packing values in serialization.
/// <seealso cref="ByteUnpacker"/> to unpack packed values.
/// </summary> /// </summary>
public static class BytePacker public static class BytePacker
{ {
@@ -282,14 +283,49 @@ namespace Unity.Netcode
public void WriteValueBitPacked<T>(FastBufferWriter writer, T value) where T: unmanaged => writer.WriteValueSafe(value); public void WriteValueBitPacked<T>(FastBufferWriter writer, T value) where T: unmanaged => writer.WriteValueSafe(value);
#else #else
/// <summary>
/// Maximum serializable value for a BitPacked ushort (minimum for unsigned is 0)
/// </summary>
public const ushort BitPackedUshortMax = (1 << 15) - 1; public const ushort BitPackedUshortMax = (1 << 15) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked short
/// </summary>
public const short BitPackedShortMax = (1 << 14) - 1; public const short BitPackedShortMax = (1 << 14) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked ushort
/// </summary>
public const short BitPackedShortMin = -(1 << 14); public const short BitPackedShortMin = -(1 << 14);
/// <summary>
/// Maximum serializable value for a BitPacked uint (minimum for unsigned is 0)
/// </summary>
public const uint BitPackedUintMax = (1 << 30) - 1; public const uint BitPackedUintMax = (1 << 30) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked int
/// </summary>
public const int BitPackedIntMax = (1 << 29) - 1; public const int BitPackedIntMax = (1 << 29) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked int
/// </summary>
public const int BitPackedIntMin = -(1 << 29); public const int BitPackedIntMin = -(1 << 29);
/// <summary>
/// Maximum serializable value for a BitPacked ulong (minimum for unsigned is 0)
/// </summary>
public const ulong BitPackedULongMax = (1L << 61) - 1; public const ulong BitPackedULongMax = (1L << 61) - 1;
/// <summary>
/// Maximum serializable value for a BitPacked long
/// </summary>
public const long BitPackedLongMax = (1L << 60) - 1; public const long BitPackedLongMax = (1L << 60) - 1;
/// <summary>
/// Minimum serializable value size for a BitPacked long
/// </summary>
public const long BitPackedLongMin = -(1L << 60); public const long BitPackedLongMin = -(1L << 60);
/// <summary> /// <summary>

View File

@@ -4,6 +4,11 @@ using UnityEngine;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Byte Unpacking Helper Class
/// Use this class to unpack values during deserialization for values that were packed.
/// <seealso cref="BytePacker"/> to pack unpacked values
/// </summary>
public static class ByteUnpacker public static class ByteUnpacker
{ {
@@ -12,6 +17,13 @@ namespace Unity.Netcode
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValuePacked<T>(FastBufferReader reader, out T value) where T: unmanaged => reader.ReadValueSafe(out value); public void ReadValuePacked<T>(FastBufferReader reader, out T value) where T: unmanaged => reader.ReadValueSafe(out value);
#else #else
/// <summary>
/// Read a packed enum value
/// </summary>
/// <param name="reader">The reader to read from</param>
/// <param name="value">The value that's read</param>
/// <typeparam name="TEnum">Type of enum to read</typeparam>
/// <exception cref="InvalidOperationException">Throws InvalidOperationException if an enum somehow ends up not being the size of a byte, short, int, or long (which should be impossible)</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void ReadValuePacked<TEnum>(FastBufferReader reader, out TEnum value) where TEnum : unmanaged, Enum public static unsafe void ReadValuePacked<TEnum>(FastBufferReader reader, out TEnum value) where TEnum : unmanaged, Enum
{ {

View File

@@ -6,6 +6,12 @@ using UnityEngine;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Optimized class used for reading values from a byte stream
/// <seealso cref="FastBufferWriter"/>
/// <seealso cref="BytePacker"/>
/// <seealso cref="ByteUnpacker"/>
/// </summary>
public struct FastBufferReader : IDisposable public struct FastBufferReader : IDisposable
{ {
internal struct ReaderHandle internal struct ReaderHandle
@@ -87,15 +93,15 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Create a FastBufferReader from a NativeArray. /// Create a FastBufferReader from a NativeArray.
/// ///
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in. /// A new buffer will be created using the given <param name="copyAllocator"></param> and the value will be copied in.
/// FastBufferReader will then own the data. /// FastBufferReader will then own the data.
/// ///
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario, /// The exception to this is when the <param name="copyAllocator"></param> passed in is Allocator.None. In this scenario,
/// ownership of the data remains with the caller and the reader will point at it directly. /// ownership of the data remains with the caller and the reader will point at it directly.
/// When created with Allocator.None, FastBufferReader will allocate some internal data using /// When created with Allocator.None, FastBufferReader will allocate some internal data using
/// Allocator.Temp so it should be treated as if it's a ref struct and not allowed to outlive /// Allocator.Temp so it should be treated as if it's a ref struct and not allowed to outlive
/// the context in which it was created (it should neither be returned from that function nor /// the context in which it was created (it should neither be returned from that function nor
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set /// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"></param> param is explicitly set
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller /// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
/// should manually call Dispose() when it is no longer needed. /// should manually call Dispose() when it is no longer needed.
/// </summary> /// </summary>
@@ -162,15 +168,15 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Create a FastBufferReader from an existing byte buffer. /// Create a FastBufferReader from an existing byte buffer.
/// ///
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in. /// A new buffer will be created using the given <param name="copyAllocator"></param> and the value will be copied in.
/// FastBufferReader will then own the data. /// FastBufferReader will then own the data.
/// ///
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario, /// The exception to this is when the <param name="copyAllocator"></param> passed in is Allocator.None. In this scenario,
/// ownership of the data remains with the caller and the reader will point at it directly. /// ownership of the data remains with the caller and the reader will point at it directly.
/// When created with Allocator.None, FastBufferReader will allocate some internal data using /// When created with Allocator.None, FastBufferReader will allocate some internal data using
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive /// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
/// the context in which it was created (it should neither be returned from that function nor /// the context in which it was created (it should neither be returned from that function nor
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set /// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"></param> param is explicitly set
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller /// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
/// should manually call Dispose() when it is no longer needed. /// should manually call Dispose() when it is no longer needed.
/// </summary> /// </summary>
@@ -187,15 +193,15 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Create a FastBufferReader from a FastBufferWriter. /// Create a FastBufferReader from a FastBufferWriter.
/// ///
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in. /// A new buffer will be created using the given <param name="copyAllocator"></param> and the value will be copied in.
/// FastBufferReader will then own the data. /// FastBufferReader will then own the data.
/// ///
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario, /// The exception to this is when the <param name="copyAllocator"></param> passed in is Allocator.None. In this scenario,
/// ownership of the data remains with the caller and the reader will point at it directly. /// ownership of the data remains with the caller and the reader will point at it directly.
/// When created with Allocator.None, FastBufferReader will allocate some internal data using /// When created with Allocator.None, FastBufferReader will allocate some internal data using
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive /// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
/// the context in which it was created (it should neither be returned from that function nor /// the context in which it was created (it should neither be returned from that function nor
/// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"> param is explicitly set /// stored anywhere in heap memory). This is true, unless the <param name="internalAllocator"></param> param is explicitly set
/// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller /// to i.e.: Allocator.Persistent in which case it would allow the internal data to Persist for longer, but the caller
/// should manually call Dispose() when it is no longer needed. /// should manually call Dispose() when it is no longer needed.
/// </summary> /// </summary>
@@ -214,10 +220,10 @@ namespace Unity.Netcode
/// want to change the copyAllocator that a reader is allocated to - for example, upgrading a Temp reader to /// want to change the copyAllocator that a reader is allocated to - for example, upgrading a Temp reader to
/// a Persistent one to be processed later. /// a Persistent one to be processed later.
/// ///
/// A new buffer will be created using the given <param name="copyAllocator"> and the value will be copied in. /// A new buffer will be created using the given <param name="copyAllocator"></param> and the value will be copied in.
/// FastBufferReader will then own the data. /// FastBufferReader will then own the data.
/// ///
/// The exception to this is when the <param name="copyAllocator"> passed in is Allocator.None. In this scenario, /// The exception to this is when the <param name="copyAllocator"></param> passed in is Allocator.None. In this scenario,
/// ownership of the data remains with the caller and the reader will point at it directly. /// ownership of the data remains with the caller and the reader will point at it directly.
/// When created with Allocator.None, FastBufferReader will allocate some internal data using /// When created with Allocator.None, FastBufferReader will allocate some internal data using
/// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive /// Allocator.Temp, so it should be treated as if it's a ref struct and not allowed to outlive
@@ -235,7 +241,7 @@ namespace Unity.Netcode
} }
/// <summary> /// <summary>
/// Frees the allocated buffer /// <see cref="IDisposable"/> implementation that frees the allocated buffer
/// </summary> /// </summary>
public unsafe void Dispose() public unsafe void Dispose()
{ {
@@ -335,6 +341,7 @@ namespace Unity.Netcode
/// for performance reasons, since the point of using TryBeginRead is to avoid bounds checking in the following /// for performance reasons, since the point of using TryBeginRead is to avoid bounds checking in the following
/// operations in release builds. /// operations in release builds.
/// </summary> /// </summary>
/// <typeparam name="T">the type `T` of the value you are trying to read</typeparam>
/// <param name="value">The value you want to read</param> /// <param name="value">The value you want to read</param>
/// <returns>True if the read is allowed, false otherwise</returns> /// <returns>True if the read is allowed, false otherwise</returns>
/// <exception cref="InvalidOperationException">If called while in a bitwise context</exception> /// <exception cref="InvalidOperationException">If called while in a bitwise context</exception>
@@ -364,7 +371,7 @@ namespace Unity.Netcode
/// Differs from TryBeginRead only in that it won't ever move the AllowedReadMark backward. /// Differs from TryBeginRead only in that it won't ever move the AllowedReadMark backward.
/// </summary> /// </summary>
/// <param name="bytes"></param> /// <param name="bytes"></param>
/// <returns></returns> /// <returns>true upon success</returns>
/// <exception cref="InvalidOperationException"></exception> /// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe bool TryBeginReadInternal(int bytes) internal unsafe bool TryBeginReadInternal(int bytes)
@@ -393,7 +400,7 @@ namespace Unity.Netcode
/// Returns an array representation of the underlying byte buffer. /// Returns an array representation of the underlying byte buffer.
/// !!Allocates a new array!! /// !!Allocates a new array!!
/// </summary> /// </summary>
/// <returns></returns> /// <returns>byte array</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte[] ToArray() public unsafe byte[] ToArray()
{ {
@@ -408,7 +415,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Gets a direct pointer to the underlying buffer /// Gets a direct pointer to the underlying buffer
/// </summary> /// </summary>
/// <returns></returns> /// <returns><see cref="byte"/> pointer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte* GetUnsafePtr() public unsafe byte* GetUnsafePtr()
{ {
@@ -418,7 +425,7 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Gets a direct pointer to the underlying buffer at the current read position /// Gets a direct pointer to the underlying buffer at the current read position
/// </summary> /// </summary>
/// <returns></returns> /// <returns><see cref="byte"/> pointer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe byte* GetUnsafePtrAtCurrentPosition() public unsafe byte* GetUnsafePtrAtCurrentPosition()
{ {
@@ -428,8 +435,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Read an INetworkSerializable /// Read an INetworkSerializable
/// </summary> /// </summary>
/// <param name="value">INetworkSerializable instance</param>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
/// <param name="value">INetworkSerializable instance</param>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
public void ReadNetworkSerializable<T>(out T value) where T : INetworkSerializable, new() public void ReadNetworkSerializable<T>(out T value) where T : INetworkSerializable, new()
{ {
@@ -442,7 +449,7 @@ namespace Unity.Netcode
/// Read an array of INetworkSerializables /// Read an array of INetworkSerializables
/// </summary> /// </summary>
/// <param name="value">INetworkSerializable instance</param> /// <param name="value">INetworkSerializable instance</param>
/// <typeparam name="T"></typeparam> /// <typeparam name="T">the array to read the values of type `T` into</typeparam>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
public void ReadNetworkSerializable<T>(out T[] value) where T : INetworkSerializable, new() public void ReadNetworkSerializable<T>(out T[] value) where T : INetworkSerializable, new()
{ {
@@ -537,7 +544,7 @@ namespace Unity.Netcode
/// <param name="value">Value to read</param> /// <param name="value">Value to read</param>
/// <param name="bytesToRead">Number of bytes</param> /// <param name="bytesToRead">Number of bytes</param>
/// <param name="offsetBytes">Offset into the value to write the bytes</param> /// <param name="offsetBytes">Offset into the value to write the bytes</param>
/// <typeparam name="T"></typeparam> /// <typeparam name="T">the type value to read the value into</typeparam>
/// <exception cref="InvalidOperationException"></exception> /// <exception cref="InvalidOperationException"></exception>
/// <exception cref="OverflowException"></exception> /// <exception cref="OverflowException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -738,127 +745,522 @@ namespace Unity.Netcode
} }
} }
/// <summary>
/// Read a NetworkSerializable value
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value); public void ReadValue<T>(out T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value);
/// <summary>
/// Read a NetworkSerializable array
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value); public void ReadValue<T>(out T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value);
/// <summary>
/// Read a NetworkSerializable value
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value); public void ReadValueSafe<T>(out T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value);
/// <summary>
/// Read a NetworkSerializable array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value); public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new() => ReadNetworkSerializable(out value);
/// <summary>
/// Read a struct
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanaged(out value); public void ReadValue<T>(out T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanaged(out value);
/// <summary>
/// Read a struct array
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanaged(out value); public void ReadValue<T>(out T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanaged(out value);
/// <summary>
/// Read a struct
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a struct array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanaged(out value); public void ReadValue<T>(out T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanaged(out value);
/// <summary>
/// Read a primitive value array (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanaged(out value); public void ReadValue<T>(out T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanaged(out value);
/// <summary>
/// Read a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => ReadUnmanagedSafe(out value);
/// <summary>
/// Read an enum value
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanaged(out value); public void ReadValue<T>(out T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanaged(out value);
/// <summary>
/// Read an enum array
/// </summary>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue<T>(out T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanaged(out value); public void ReadValue<T>(out T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanaged(out value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <summary>
/// Read an enum value
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanagedSafe(out value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <summary>
/// Read an enum array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanagedSafe(out value); public void ReadValueSafe<T>(out T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector2
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector2 value) => ReadUnmanaged(out value); public void ReadValue(out Vector2 value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector2 array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector2[] value) => ReadUnmanaged(out value); public void ReadValue(out Vector2[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector3
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector3 value) => ReadUnmanaged(out value); public void ReadValue(out Vector3 value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector3 array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector3[] value) => ReadUnmanaged(out value); public void ReadValue(out Vector3[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector2Int
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector2Int value) => ReadUnmanaged(out value); public void ReadValue(out Vector2Int value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector2Int array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector2Int[] value) => ReadUnmanaged(out value); public void ReadValue(out Vector2Int[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector3Int
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector3Int value) => ReadUnmanaged(out value); public void ReadValue(out Vector3Int value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector3Int array
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector3Int[] value) => ReadUnmanaged(out value); public void ReadValue(out Vector3Int[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector4
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector4 value) => ReadUnmanaged(out value); public void ReadValue(out Vector4 value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector4
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Vector4[] value) => ReadUnmanaged(out value); public void ReadValue(out Vector4[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Quaternion
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Quaternion value) => ReadUnmanaged(out value); public void ReadValue(out Quaternion value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Quaternion array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Quaternion[] value) => ReadUnmanaged(out value); public void ReadValue(out Quaternion[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Color
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Color value) => ReadUnmanaged(out value); public void ReadValue(out Color value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Color array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Color[] value) => ReadUnmanaged(out value); public void ReadValue(out Color[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Color32
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Color32 value) => ReadUnmanaged(out value); public void ReadValue(out Color32 value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Color32 array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Color32[] value) => ReadUnmanaged(out value); public void ReadValue(out Color32[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Ray
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Ray value) => ReadUnmanaged(out value); public void ReadValue(out Ray value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Ray array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Ray[] value) => ReadUnmanaged(out value); public void ReadValue(out Ray[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Ray2D
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Ray2D value) => ReadUnmanaged(out value); public void ReadValue(out Ray2D value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Ray2D array
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValue(out Ray2D[] value) => ReadUnmanaged(out value); public void ReadValue(out Ray2D[] value) => ReadUnmanaged(out value);
/// <summary>
/// Read a Vector2
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector2 value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector2 value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector2 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector2[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector2[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector3
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector3 value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector3 value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector3 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector3[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector3[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector2Int
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector2Int value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector2Int value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector2Int array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector2Int[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector2Int[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector3Int
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector3Int value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector3Int value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector3Int array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector3Int[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector3Int[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector4
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector4 value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector4 value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Vector4 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Vector4[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Vector4[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Quaternion
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Quaternion value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Quaternion value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Quaternion array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Quaternion[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Quaternion[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Color
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Color value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Color value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Collor array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Color[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Color[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Color32
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Color32 value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Color32 value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Color32 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Color32[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Color32[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Ray
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Ray value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Ray value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Ray array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Ray[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Ray[] value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Ray2D
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Ray2D value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Ray2D value) => ReadUnmanagedSafe(out value);
/// <summary>
/// Read a Ray2D array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the values to read</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadValueSafe(out Ray2D[] value) => ReadUnmanagedSafe(out value); public void ReadValueSafe(out Ray2D[] value) => ReadUnmanagedSafe(out value);
@@ -868,6 +1270,17 @@ namespace Unity.Netcode
// Those two are necessary to serialize FixedStrings efficiently // Those two are necessary to serialize FixedStrings efficiently
// - otherwise we'd just be memcpying the whole thing even if // - otherwise we'd just be memcpying the whole thing even if
// most of it isn't used. // most of it isn't used.
/// <summary>
/// Read a FixedString value.
/// This method is a little difficult to use, since you have to know the size of the string before
/// reading it, but is useful when the string is a known, fixed size. Note that the size of the
/// string is also encoded, so the size to call TryBeginRead on is actually the fixed size (in bytes)
/// plus sizeof(int)
/// </summary>
/// <param name="value">the value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void ReadValue<T>(out T value, FastBufferWriter.ForFixedStrings unused = default) public unsafe void ReadValue<T>(out T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes where T : unmanaged, INativeList<byte>, IUTF8Bytes
@@ -878,6 +1291,16 @@ namespace Unity.Netcode
ReadBytes(value.GetUnsafePtr(), length); ReadBytes(value.GetUnsafePtr(), length);
} }
/// <summary>
/// Read a FixedString value.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple reads at once by calling TryBeginRead.
/// </summary>
/// <param name="value">the value to read</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void ReadValueSafe<T>(out T value, FastBufferWriter.ForFixedStrings unused = default) public unsafe void ReadValueSafe<T>(out T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes where T : unmanaged, INativeList<byte>, IUTF8Bytes

View File

@@ -6,6 +6,12 @@ using UnityEngine;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Optimized class used for writing values into a byte stream
/// <seealso cref="FastBufferReader"/>
/// <seealso cref="BytePacker"/>
/// <seealso cref="ByteUnpacker"/>
/// </summary>
public struct FastBufferWriter : IDisposable public struct FastBufferWriter : IDisposable
{ {
internal struct WriterHandle internal struct WriterHandle
@@ -108,7 +114,7 @@ namespace Unity.Netcode
} }
/// <summary> /// <summary>
/// Frees the allocated buffer /// <see cref="IDisposable"/> implementation that frees the allocated buffer
/// </summary> /// </summary>
public unsafe void Dispose() public unsafe void Dispose()
{ {
@@ -267,7 +273,8 @@ namespace Unity.Netcode
/// operations in release builds. Instead, attempting to write past the marked position in release builds /// operations in release builds. Instead, attempting to write past the marked position in release builds
/// will write to random memory and cause undefined behavior, likely including instability and crashes. /// will write to random memory and cause undefined behavior, likely including instability and crashes.
/// </summary> /// </summary>
/// <param name="value">The value you want to write</param> /// <typeparam name="T">The value type to write</typeparam>
/// <param name="value">The value of the type `T` you want to write</param>
/// <returns>True if the write is allowed, false otherwise</returns> /// <returns>True if the write is allowed, false otherwise</returns>
/// <exception cref="InvalidOperationException">If called while in a bitwise context</exception> /// <exception cref="InvalidOperationException">If called while in a bitwise context</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -792,151 +799,590 @@ namespace Unity.Netcode
} }
} }
// These structs enable overloading of WriteValue with different generic constraints. /// <summary>
// The compiler's actually able to distinguish between overloads based on generic constraints. /// This empty struct exists to allow overloading WriteValue based on generic constraints.
// But at the bytecode level, the constraints aren't included in the method signature. /// At the bytecode level, constraints aren't included in the method signature, so if multiple
// By adding a second parameter with a defaulted value, the signatures of each generic are different, /// methods exist with the same signature, it causes a compile error because they would end up
// thus allowing overloads of methods based on the first parameter meeting constraints. /// being emitted as the same method, even if the constraints are different.
/// Adding an empty struct with a default value gives them different signatures in the bytecode,
/// which then allows the compiler to do overload resolution based on the generic constraints
/// without the user having to pass the struct in themselves.
/// </summary>
public struct ForPrimitives public struct ForPrimitives
{ {
} }
/// <summary>
/// This empty struct exists to allow overloading WriteValue based on generic constraints.
/// At the bytecode level, constraints aren't included in the method signature, so if multiple
/// methods exist with the same signature, it causes a compile error because they would end up
/// being emitted as the same method, even if the constraints are different.
/// Adding an empty struct with a default value gives them different signatures in the bytecode,
/// which then allows the compiler to do overload resolution based on the generic constraints
/// without the user having to pass the struct in themselves.
/// </summary>
public struct ForEnums public struct ForEnums
{ {
} }
/// <summary>
/// This empty struct exists to allow overloading WriteValue based on generic constraints.
/// At the bytecode level, constraints aren't included in the method signature, so if multiple
/// methods exist with the same signature, it causes a compile error because they would end up
/// being emitted as the same method, even if the constraints are different.
/// Adding an empty struct with a default value gives them different signatures in the bytecode,
/// which then allows the compiler to do overload resolution based on the generic constraints
/// without the user having to pass the struct in themselves.
/// </summary>
public struct ForStructs public struct ForStructs
{ {
} }
/// <summary>
/// This empty struct exists to allow overloading WriteValue based on generic constraints.
/// At the bytecode level, constraints aren't included in the method signature, so if multiple
/// methods exist with the same signature, it causes a compile error because they would end up
/// being emitted as the same method, even if the constraints are different.
/// Adding an empty struct with a default value gives them different signatures in the bytecode,
/// which then allows the compiler to do overload resolution based on the generic constraints
/// without the user having to pass the struct in themselves.
/// </summary>
public struct ForNetworkSerializable public struct ForNetworkSerializable
{ {
} }
/// <summary>
/// This empty struct exists to allow overloading WriteValue based on generic constraints.
/// At the bytecode level, constraints aren't included in the method signature, so if multiple
/// methods exist with the same signature, it causes a compile error because they would end up
/// being emitted as the same method, even if the constraints are different.
/// Adding an empty struct with a default value gives them different signatures in the bytecode,
/// which then allows the compiler to do overload resolution based on the generic constraints
/// without the user having to pass the struct in themselves.
/// </summary>
public struct ForFixedStrings public struct ForFixedStrings
{ {
} }
/// <summary>
/// Write a NetworkSerializable value
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value); public void WriteValue<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
/// <summary>
/// Write a NetworkSerializable array
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value); public void WriteValue<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
/// <summary>
/// Write a NetworkSerializable value
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value); public void WriteValueSafe<T>(in T value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
/// <summary>
/// Write a NetworkSerializable array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value); public void WriteValueSafe<T>(T[] value, ForNetworkSerializable unused = default) where T : INetworkSerializable => WriteNetworkSerializable(value);
/// <summary>
/// Write a struct
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value); public void WriteValue<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value);
/// <summary>
/// Write a struct array
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value); public void WriteValue<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanaged(value);
/// <summary>
/// Write a struct
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(in T value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value);
/// <summary>
/// Write a struct array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(T[] value, ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy => WriteUnmanagedSafe(value);
/// <summary>
/// Write a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value); public void WriteValue<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value);
/// <summary>
/// Write a primitive value array (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value); public void WriteValue<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanaged(value);
/// <summary>
/// Write a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(in T value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value);
/// <summary>
/// Write a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(T[] value, ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T> => WriteUnmanagedSafe(value);
/// <summary>
/// Write an enum value
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value); public void WriteValue<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value);
/// <summary>
/// Write an enum array
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value); public void WriteValue<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanaged(value);
/// <summary>
/// Write an enum value
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(in T value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value);
/// <summary>
/// Write an enum array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">The values to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value); public void WriteValueSafe<T>(T[] value, ForEnums unused = default) where T : unmanaged, Enum => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector2
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Vector2 value) => WriteUnmanaged(value); public void WriteValue(in Vector2 value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector2 array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Vector2[] value) => WriteUnmanaged(value); public void WriteValue(Vector2[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector3
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Vector3 value) => WriteUnmanaged(value); public void WriteValue(in Vector3 value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector3 array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Vector3[] value) => WriteUnmanaged(value); public void WriteValue(Vector3[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector2Int
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Vector2Int value) => WriteUnmanaged(value); public void WriteValue(in Vector2Int value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector2Int array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Vector2Int[] value) => WriteUnmanaged(value); public void WriteValue(Vector2Int[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector3Int
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Vector3Int value) => WriteUnmanaged(value); public void WriteValue(in Vector3Int value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector3Int array
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Vector3Int[] value) => WriteUnmanaged(value); public void WriteValue(Vector3Int[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector4
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Vector4 value) => WriteUnmanaged(value); public void WriteValue(in Vector4 value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector4
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Vector4[] value) => WriteUnmanaged(value); public void WriteValue(Vector4[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Quaternion
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Quaternion value) => WriteUnmanaged(value); public void WriteValue(in Quaternion value) => WriteUnmanaged(value);
/// <summary>
/// Write a Quaternion array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Quaternion[] value) => WriteUnmanaged(value); public void WriteValue(Quaternion[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Color
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Color value) => WriteUnmanaged(value); public void WriteValue(in Color value) => WriteUnmanaged(value);
/// <summary>
/// Write a Color array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Color[] value) => WriteUnmanaged(value); public void WriteValue(Color[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Color32
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Color32 value) => WriteUnmanaged(value); public void WriteValue(in Color32 value) => WriteUnmanaged(value);
/// <summary>
/// Write a Color32 array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Color32[] value) => WriteUnmanaged(value); public void WriteValue(Color32[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Ray
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Ray value) => WriteUnmanaged(value); public void WriteValue(in Ray value) => WriteUnmanaged(value);
/// <summary>
/// Write a Ray array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Ray[] value) => WriteUnmanaged(value); public void WriteValue(Ray[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Ray2D
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(in Ray2D value) => WriteUnmanaged(value); public void WriteValue(in Ray2D value) => WriteUnmanaged(value);
/// <summary>
/// Write a Ray2D array
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValue(Ray2D[] value) => WriteUnmanaged(value); public void WriteValue(Ray2D[] value) => WriteUnmanaged(value);
/// <summary>
/// Write a Vector2
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Vector2 value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Vector2 value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector2 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Vector2[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Vector2[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector3
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Vector3 value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Vector3 value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector3 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Vector3[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Vector3[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector2Int
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Vector2Int value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Vector2Int value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector2Int array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Vector2Int[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Vector2Int[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector3Int
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Vector3Int value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Vector3Int value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector3Int array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Vector3Int[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Vector3Int[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector4
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Vector4 value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Vector4 value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Vector4 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Vector4[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Vector4[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Quaternion
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Quaternion value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Quaternion value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Quaternion array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Quaternion[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Quaternion[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Color
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Color value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Color value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Collor array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Color[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Color[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Color32
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Color32 value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Color32 value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Color32 array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Color32[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Color32[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Ray
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Ray value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Ray value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Ray array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Ray[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Ray[] value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Ray2D
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(in Ray2D value) => WriteUnmanagedSafe(value); public void WriteValueSafe(in Ray2D value) => WriteUnmanagedSafe(value);
/// <summary>
/// Write a Ray2D array
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the values to write</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe(Ray2D[] value) => WriteUnmanagedSafe(value); public void WriteValueSafe(Ray2D[] value) => WriteUnmanagedSafe(value);
@@ -946,6 +1392,15 @@ namespace Unity.Netcode
// Those two are necessary to serialize FixedStrings efficiently // Those two are necessary to serialize FixedStrings efficiently
// - otherwise we'd just be memcpying the whole thing even if // - otherwise we'd just be memcpying the whole thing even if
// most of it isn't used. // most of it isn't used.
/// <summary>
/// Write a FixedString value. Writes only the part of the string that's actually used.
/// When calling TryBeginWrite, ensure you calculate the write size correctly (preferably by calling
/// FastBufferWriter.GetWriteSize())
/// </summary>
/// <param name="value">the value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void WriteValue<T>(in T value, ForFixedStrings unused = default) public unsafe void WriteValue<T>(in T value, ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes where T : unmanaged, INativeList<byte>, IUTF8Bytes
@@ -960,6 +1415,16 @@ namespace Unity.Netcode
} }
} }
/// <summary>
/// Write a FixedString value. Writes only the part of the string that's actually used.
///
/// "Safe" version - automatically performs bounds checking. Less efficient than bounds checking
/// for multiple writes at once by calling TryBeginWrite.
/// </summary>
/// <param name="value">the value to write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteValueSafe<T>(in T value, ForFixedStrings unused = default) public void WriteValueSafe<T>(in T value, ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes where T : unmanaged, INativeList<byte>, IUTF8Bytes

View File

@@ -9,26 +9,58 @@ namespace Unity.Netcode
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public struct ForceNetworkSerializeByMemcpy<T> : INetworkSerializeByMemcpy, IEquatable<ForceNetworkSerializeByMemcpy<T>> where T : unmanaged, IEquatable<T> public struct ForceNetworkSerializeByMemcpy<T> : INetworkSerializeByMemcpy, IEquatable<ForceNetworkSerializeByMemcpy<T>> where T : unmanaged, IEquatable<T>
{ {
/// <summary>
/// The wrapped value
/// </summary>
public T Value; public T Value;
/// <summary>
/// The default constructor for <see cref="ForceNetworkSerializeByMemcpy{T}"/>
/// </summary>
/// <param name="value">sets the initial value of type `T`</param>
public ForceNetworkSerializeByMemcpy(T value) public ForceNetworkSerializeByMemcpy(T value)
{ {
Value = value; Value = value;
} }
/// <summary>
/// Convert implicitly from the ForceNetworkSerializeByMemcpy wrapper to the underlying value
/// </summary>
/// <param name="container">The wrapper</param>
/// <returns>The underlying value</returns>
public static implicit operator T(ForceNetworkSerializeByMemcpy<T> container) => container.Value; public static implicit operator T(ForceNetworkSerializeByMemcpy<T> container) => container.Value;
/// <summary>
/// Convert implicitly from a T value to a ForceNetworkSerializeByMemcpy wrapper
/// </summary>
/// <param name="underlyingValue">the value</param>
/// <returns>a new wrapper</returns>
public static implicit operator ForceNetworkSerializeByMemcpy<T>(T underlyingValue) => new ForceNetworkSerializeByMemcpy<T> { Value = underlyingValue }; public static implicit operator ForceNetworkSerializeByMemcpy<T>(T underlyingValue) => new ForceNetworkSerializeByMemcpy<T> { Value = underlyingValue };
/// <summary>
/// Check if wrapped values are equal
/// </summary>
/// <param name="other">Other wrapper</param>
/// <returns>true if equal</returns>
public bool Equals(ForceNetworkSerializeByMemcpy<T> other) public bool Equals(ForceNetworkSerializeByMemcpy<T> other)
{ {
return Value.Equals(other.Value); return Value.Equals(other.Value);
} }
/// <summary>
/// Check if this value is equal to a boxed object value
/// </summary>
/// <param name="obj">The boxed value to check against</param>
/// <returns>true if equal</returns>
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is ForceNetworkSerializeByMemcpy<T> other && Equals(other); return obj is ForceNetworkSerializeByMemcpy<T> other && Equals(other);
} }
/// <summary>
/// Obtains the wrapped value's hash code
/// </summary>
/// <returns>Wrapped value's hash code</returns>
public override int GetHashCode() public override int GetHashCode()
{ {
return Value.GetHashCode(); return Value.GetHashCode();

View File

@@ -6,7 +6,7 @@ namespace Unity.Netcode
/// by memcpy. It's up to the developer of the struct to analyze the struct's contents and ensure it /// by memcpy. It's up to the developer of the struct to analyze the struct's contents and ensure it
/// is actually serializable by memcpy. This requires all of the members of the struct to be /// is actually serializable by memcpy. This requires all of the members of the struct to be
/// `unmanaged` Plain-Old-Data values - if your struct contains a pointer (or a type that contains a pointer, /// `unmanaged` Plain-Old-Data values - if your struct contains a pointer (or a type that contains a pointer,
/// like `NativeList<T>`), it should be serialized via `INetworkSerializable` or via /// like `NativeList&lt;T&gt;`), it should be serialized via `INetworkSerializable` or via
/// `FastBufferReader`/`FastBufferWriter` extension methods. /// `FastBufferReader`/`FastBufferWriter` extension methods.
/// </summary> /// </summary>
public interface INetworkSerializeByMemcpy public interface INetworkSerializeByMemcpy

View File

@@ -4,81 +4,536 @@ using UnityEngine;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Interface for an implementation of one side of a two-way serializer
/// </summary>
public interface IReaderWriter public interface IReaderWriter
{ {
/// <summary>
/// Check whether this implementation is a "reader" - if it's been constructed to deserialize data
/// </summary>
bool IsReader { get; } bool IsReader { get; }
/// <summary>
/// Check whether this implementation is a "writer" - if it's been constructed to serialize data
/// </summary>
bool IsWriter { get; } bool IsWriter { get; }
/// <summary>
/// Get the underlying FastBufferReader struct.
/// Only valid when IsReader == true
/// </summary>
/// <returns>underlying FastBufferReader</returns>
FastBufferReader GetFastBufferReader(); FastBufferReader GetFastBufferReader();
/// <summary>
/// Get the underlying FastBufferWriter struct.
/// Only valid when IsWriter == true
/// </summary>
/// <returns>underlying FastBufferWriter</returns>
FastBufferWriter GetFastBufferWriter(); FastBufferWriter GetFastBufferWriter();
/// <summary>
/// Read or write a string
/// </summary>
/// <param name="s">The value to read/write</param>
/// <param name="oneByteChars">If true, characters will be limited to one-byte ASCII characters</param>
void SerializeValue(ref string s, bool oneByteChars = false); void SerializeValue(ref string s, bool oneByteChars = false);
/// <summary>
/// Read or write a single byte
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref byte value); void SerializeValue(ref byte value);
/// <summary>
/// Read or write a primitive value (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>; void SerializeValue<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>;
/// <summary>
/// Read or write an array of primitive values (int, bool, etc)
/// Accepts any value that implements the given interfaces, but is not guaranteed to work correctly
/// on values that are not primitives.
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>; void SerializeValue<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>;
/// <summary>
/// Read or write an enum value
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum; void SerializeValue<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum;
/// <summary>
/// Read or write an array of enum values
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum; void SerializeValue<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum;
/// <summary>
/// Read or write a struct value implementing ISerializeByMemcpy
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy; void SerializeValue<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy;
/// <summary>
/// Read or write an array of struct values implementing ISerializeByMemcpy
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy; void SerializeValue<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy;
/// <summary>
/// Read or write a struct or class value implementing INetworkSerializable
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new(); void SerializeValue<T>(ref T value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new();
/// <summary>
/// Read or write an array of struct or class values implementing INetworkSerializable
/// </summary>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new(); void SerializeValue<T>(ref T[] value, FastBufferWriter.ForNetworkSerializable unused = default) where T : INetworkSerializable, new();
/// <summary>
/// Read or write a FixedString value
/// </summary>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter used for enabling overload resolution based on generic constraints</param>
/// <typeparam name="T">The type being serialized</typeparam>
void SerializeValue<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default) void SerializeValue<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes; where T : unmanaged, INativeList<byte>, IUTF8Bytes;
/// <summary>
/// Read or write a Vector2 value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Vector2 value); void SerializeValue(ref Vector2 value);
/// <summary>
/// Read or write an array of Vector2 values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Vector2[] value); void SerializeValue(ref Vector2[] value);
/// <summary>
/// Read or write a Vector3 value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Vector3 value); void SerializeValue(ref Vector3 value);
/// <summary>
/// Read or write an array of Vector3 values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Vector3[] value); void SerializeValue(ref Vector3[] value);
/// <summary>
/// Read or write a Vector2Int value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Vector2Int value); void SerializeValue(ref Vector2Int value);
/// <summary>
/// Read or write an array of Vector2Int values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Vector2Int[] value); void SerializeValue(ref Vector2Int[] value);
/// <summary>
/// Read or write a Vector3Int value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Vector3Int value); void SerializeValue(ref Vector3Int value);
/// <summary>
/// Read or write an array of Vector3Int values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Vector3Int[] value); void SerializeValue(ref Vector3Int[] value);
/// <summary>
/// Read or write a Vector4 value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Vector4 value); void SerializeValue(ref Vector4 value);
/// <summary>
/// Read or write an array of Vector4 values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Vector4[] value); void SerializeValue(ref Vector4[] value);
/// <summary>
/// Read or write a Quaternion value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Quaternion value); void SerializeValue(ref Quaternion value);
/// <summary>
/// Read or write an array of Quaternion values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Quaternion[] value); void SerializeValue(ref Quaternion[] value);
/// <summary>
/// Read or write a Color value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Color value); void SerializeValue(ref Color value);
/// <summary>
/// Read or write an array of Color values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Color[] value); void SerializeValue(ref Color[] value);
/// <summary>
/// Read or write a Color32 value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Color32 value); void SerializeValue(ref Color32 value);
/// <summary>
/// Read or write an array of Color32 values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Color32[] value); void SerializeValue(ref Color32[] value);
/// <summary>
/// Read or write a Ray value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Ray value); void SerializeValue(ref Ray value);
/// <summary>
/// Read or write an array of Ray values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Ray[] value); void SerializeValue(ref Ray[] value);
/// <summary>
/// Read or write a Ray2D value
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValue(ref Ray2D value); void SerializeValue(ref Ray2D value);
/// <summary>
/// Read or write an array of Ray2D values
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValue(ref Ray2D[] value); void SerializeValue(ref Ray2D[] value);
// Has to have a different name to avoid conflicting with "where T: unmananged" /// <summary>
/// Read or write a NetworkSerializable value.
/// SerializeValue() is the preferred method to do this - this is provided for backward compatibility only.
/// </summary>
/// <param name="value">The value to read/write</param>
/// <typeparam name="T">The network serializable type</typeparam>
void SerializeNetworkSerializable<T>(ref T value) where T : INetworkSerializable, new(); void SerializeNetworkSerializable<T>(ref T value) where T : INetworkSerializable, new();
/// <summary>
/// Performs an advance check to ensure space is available to read/write one or more values.
/// This provides a performance benefit for serializing multiple values using the
/// SerializeValuePreChecked methods. But note that the benefit is small and only likely to be
/// noticeable if serializing a very large number of items.
/// </summary>
/// <param name="amount"></param>
/// <returns></returns>
bool PreCheck(int amount); bool PreCheck(int amount);
/// <summary>
/// Serialize a string, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="s">The value to read/write</param>
/// <param name="oneByteChars">If true, characters will be limited to one-byte ASCII characters</param>
void SerializeValuePreChecked(ref string s, bool oneByteChars = false); void SerializeValuePreChecked(ref string s, bool oneByteChars = false);
/// <summary>
/// Serialize a byte, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref byte value); void SerializeValuePreChecked(ref byte value);
/// <summary>
/// Serialize a primitive, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>; void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>;
/// <summary>
/// Serialize an array of primitives, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>; void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForPrimitives unused = default) where T : unmanaged, IComparable, IConvertible, IComparable<T>, IEquatable<T>;
/// <summary>
/// Serialize an enum, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum; void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum;
/// <summary>
/// Serialize an array of enums, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum; void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForEnums unused = default) where T : unmanaged, Enum;
/// <summary>
/// Serialize a struct, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy; void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy;
/// <summary>
/// Serialize an array of structs, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The values to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy; void SerializeValuePreChecked<T>(ref T[] value, FastBufferWriter.ForStructs unused = default) where T : unmanaged, INetworkSerializeByMemcpy;
/// <summary>
/// Serialize a FixedString, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <typeparam name="T">The type being serialized</typeparam>
/// <param name="value">The value to read/write</param>
/// <param name="unused">An unused parameter that can be used for enabling overload resolution based on generic constraints</param>
void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default) void SerializeValuePreChecked<T>(ref T value, FastBufferWriter.ForFixedStrings unused = default)
where T : unmanaged, INativeList<byte>, IUTF8Bytes; where T : unmanaged, INativeList<byte>, IUTF8Bytes;
/// <summary>
/// Serialize a Vector2, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector2 value); void SerializeValuePreChecked(ref Vector2 value);
/// <summary>
/// Serialize a Vector2 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValuePreChecked(ref Vector2[] value); void SerializeValuePreChecked(ref Vector2[] value);
/// <summary>
/// Serialize a Vector3, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector3 value); void SerializeValuePreChecked(ref Vector3 value);
/// <summary>
/// Serialize a Vector3 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValuePreChecked(ref Vector3[] value); void SerializeValuePreChecked(ref Vector3[] value);
/// <summary>
/// Serialize a Vector2Int, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector2Int value); void SerializeValuePreChecked(ref Vector2Int value);
/// <summary>
/// Serialize a Vector2Int array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The values to read/write</param>
void SerializeValuePreChecked(ref Vector2Int[] value); void SerializeValuePreChecked(ref Vector2Int[] value);
/// <summary>
/// Serialize a Vector3Int, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector3Int value); void SerializeValuePreChecked(ref Vector3Int value);
/// <summary>
/// Serialize a Vector3Int array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector3Int[] value); void SerializeValuePreChecked(ref Vector3Int[] value);
/// <summary>
/// Serialize a Vector4, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector4 value); void SerializeValuePreChecked(ref Vector4 value);
/// <summary>
/// Serialize a Vector4Array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Vector4[] value); void SerializeValuePreChecked(ref Vector4[] value);
/// <summary>
/// Serialize a Quaternion, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Quaternion value); void SerializeValuePreChecked(ref Quaternion value);
/// <summary>
/// Serialize a Quaternion array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Quaternion[] value); void SerializeValuePreChecked(ref Quaternion[] value);
/// <summary>
/// Serialize a Color, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Color value); void SerializeValuePreChecked(ref Color value);
/// <summary>
/// Serialize a Color array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Color[] value); void SerializeValuePreChecked(ref Color[] value);
/// <summary>
/// Serialize a Color32, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Color32 value); void SerializeValuePreChecked(ref Color32 value);
/// <summary>
/// Serialize a Color32 array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Color32[] value); void SerializeValuePreChecked(ref Color32[] value);
/// <summary>
/// Serialize a Ray, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Ray value); void SerializeValuePreChecked(ref Ray value);
/// <summary>
/// Serialize a Ray array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Ray[] value); void SerializeValuePreChecked(ref Ray[] value);
/// <summary>
/// Serialize a Ray2D, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Ray2D value); void SerializeValuePreChecked(ref Ray2D value);
/// <summary>
/// Serialize a Ray2D array, "pre-checked", which skips buffer checks.
/// In debug and editor builds, a check is made to ensure you've called "PreCheck" before
/// calling this. In release builds, calling this without calling "PreCheck" may read or write
/// past the end of the buffer, which will cause memory corruption and undefined behavior.
/// </summary>
/// <param name="value">The value to read/write</param>
void SerializeValuePreChecked(ref Ray2D[] value); void SerializeValuePreChecked(ref Ray2D[] value);
} }
} }

View File

@@ -96,8 +96,18 @@ namespace Unity.Netcode
serializer.SerializeValue(ref m_NetworkBehaviourId); serializer.SerializeValue(ref m_NetworkBehaviourId);
} }
/// <summary>
/// Implicitly convert <see cref="NetworkBehaviourReference"/> to <see cref="NetworkBehaviour"/>.
/// </summary>
/// <param name="networkBehaviourRef">The <see cref="NetworkBehaviourReference"/> to convert from.</param>
/// <returns>The <see cref="NetworkBehaviour"/> this class is holding a reference to</returns>
public static implicit operator NetworkBehaviour(NetworkBehaviourReference networkBehaviourRef) => GetInternal(networkBehaviourRef); public static implicit operator NetworkBehaviour(NetworkBehaviourReference networkBehaviourRef) => GetInternal(networkBehaviourRef);
/// <summary>
/// Implicitly convert <see cref="NetworkBehaviour"/> to <see cref="NetworkBehaviourReference"/>.
/// </summary>
/// <param name="networkBehaviour">The <see cref="NetworkBehaviour"/> to convert from.</param>
/// <returns>The <see cref="NetworkBehaviourReference"/> created from the <see cref="NetworkBehaviour"/> passed in as a parameter</returns>
public static implicit operator NetworkBehaviourReference(NetworkBehaviour networkBehaviour) => new NetworkBehaviourReference(networkBehaviour); public static implicit operator NetworkBehaviourReference(NetworkBehaviour networkBehaviour) => new NetworkBehaviourReference(networkBehaviour);
} }
} }

View File

@@ -120,12 +120,32 @@ namespace Unity.Netcode
serializer.SerializeValue(ref m_NetworkObjectId); serializer.SerializeValue(ref m_NetworkObjectId);
} }
/// <summary>
/// Implicitly convert <see cref="NetworkObjectReference"/> to <see cref="NetworkObject"/>.
/// </summary>
/// <param name="networkObjectRef">The <see cref="NetworkObjectReference"/> to convert from.</param>
/// <returns>The <see cref="NetworkObject"/> the <see cref="NetworkObjectReference"/> is referencing</returns>
public static implicit operator NetworkObject(NetworkObjectReference networkObjectRef) => Resolve(networkObjectRef); public static implicit operator NetworkObject(NetworkObjectReference networkObjectRef) => Resolve(networkObjectRef);
/// <summary>
/// Implicitly convert <see cref="NetworkObject"/> to <see cref="NetworkObjectReference"/>.
/// </summary>
/// <param name="networkObject">The <see cref="NetworkObject"/> to convert from.</param>
/// <returns>The <see cref="NetworkObjectReference"/> created from the <see cref="NetworkObject"/> parameter</returns>
public static implicit operator NetworkObjectReference(NetworkObject networkObject) => new NetworkObjectReference(networkObject); public static implicit operator NetworkObjectReference(NetworkObject networkObject) => new NetworkObjectReference(networkObject);
/// <summary>
/// Implicitly convert <see cref="NetworkObjectReference"/> to <see cref="GameObject"/>.
/// </summary>
/// <param name="networkObjectRef">The <see cref="NetworkObjectReference"/> to convert from.</param>
/// <returns>This returns the <see cref="GameObject"/> that the <see cref="NetworkObject"/> is attached to and is referenced by the <see cref="NetworkObjectReference"/> passed in as a parameter</returns>
public static implicit operator GameObject(NetworkObjectReference networkObjectRef) => Resolve(networkObjectRef).gameObject; public static implicit operator GameObject(NetworkObjectReference networkObjectRef) => Resolve(networkObjectRef).gameObject;
/// <summary>
/// Implicitly convert <see cref="GameObject"/> to <see cref="NetworkObject"/>.
/// </summary>
/// <param name="gameObject">The <see cref="GameObject"/> to convert from.</param>
/// <returns>The <see cref="NetworkObjectReference"/> created from the <see cref="GameObject"/> parameter that has a <see cref="NetworkObject"/> component attached to it</returns>
public static implicit operator NetworkObjectReference(GameObject gameObject) => new NetworkObjectReference(gameObject); public static implicit operator NetworkObjectReference(GameObject gameObject) => new NetworkObjectReference(gameObject);
} }
} }

View File

@@ -126,6 +126,7 @@ namespace Unity.Netcode
/// Returns a list of all NetworkObjects that belong to a client. /// Returns a list of all NetworkObjects that belong to a client.
/// </summary> /// </summary>
/// <param name="clientId">the client's id <see cref="NetworkManager.LocalClientId"/></param> /// <param name="clientId">the client's id <see cref="NetworkManager.LocalClientId"/></param>
/// <returns>returns the list of <see cref="NetworkObject"/>s owned by the client</returns>
public List<NetworkObject> GetClientOwnedObjects(ulong clientId) public List<NetworkObject> GetClientOwnedObjects(ulong clientId)
{ {
if (!OwnershipToObjectsTable.ContainsKey(clientId)) if (!OwnershipToObjectsTable.ContainsKey(clientId))
@@ -172,9 +173,11 @@ namespace Unity.Netcode
return GetPlayerNetworkObject(NetworkManager.LocalClientId); return GetPlayerNetworkObject(NetworkManager.LocalClientId);
} }
/// <summary> /// <summary>
/// Returns the player object with a given clientId or null if one does not exist. This is only valid server side. /// Returns the player object with a given clientId or null if one does not exist. This is only valid server side.
/// </summary> /// </summary>
/// <param name="clientId">the client identifier of the player</param>
/// <returns>The player object with a given clientId or null if one does not exist</returns> /// <returns>The player object with a given clientId or null if one does not exist</returns>
public NetworkObject GetPlayerNetworkObject(ulong clientId) public NetworkObject GetPlayerNetworkObject(ulong clientId)
{ {

View File

@@ -3,6 +3,10 @@ using Unity.Profiling;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// Provides discretized time.
/// This is useful for games that require ticks happening at regular interval on the server and clients.
/// </summary>
public class NetworkTickSystem public class NetworkTickSystem
{ {
#if DEVELOPMENT_BUILD || UNITY_EDITOR #if DEVELOPMENT_BUILD || UNITY_EDITOR
@@ -69,6 +73,8 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Called after advancing the time system to run ticks based on the difference in time. /// Called after advancing the time system to run ticks based on the difference in time.
/// </summary> /// </summary>
/// <param name="localTimeSec">The local time in seconds</param>
/// <param name="serverTimeSec">The server time in seconds</param>
public void UpdateTick(double localTimeSec, double serverTimeSec) public void UpdateTick(double localTimeSec, double serverTimeSec)
{ {
// store old local tick to know how many fixed ticks passed // store old local tick to know how many fixed ticks passed

View File

@@ -108,6 +108,11 @@ namespace Unity.Netcode
return new NetworkTime(m_TickRate, m_CachedTick); return new NetworkTime(m_TickRate, m_CachedTick);
} }
/// <summary>
/// Returns the time a number of ticks in the past.
/// </summary>
/// <param name="ticks">The number of ticks ago we're querying the time</param>
/// <returns></returns>
public NetworkTime TimeTicksAgo(int ticks) public NetworkTime TimeTicksAgo(int ticks)
{ {
return this - new NetworkTime(TickRate, ticks); return this - new NetworkTime(TickRate, ticks);
@@ -132,16 +137,34 @@ namespace Unity.Netcode
} }
} }
/// <summary>
/// Computes the time difference between two ticks
/// </summary>
/// <param name="a">End time</param>
/// <param name="b">Start time</param>
/// <returns>The time difference between start and end</returns>
public static NetworkTime operator -(NetworkTime a, NetworkTime b) public static NetworkTime operator -(NetworkTime a, NetworkTime b)
{ {
return new NetworkTime(a.TickRate, a.Time - b.Time); return new NetworkTime(a.TickRate, a.Time - b.Time);
} }
/// <summary>
/// Computes the sum of two times
/// </summary>
/// <param name="a">First time</param>
/// <param name="b">Second time</param>
/// <returns>The sum of the two times passed in</returns>
public static NetworkTime operator +(NetworkTime a, NetworkTime b) public static NetworkTime operator +(NetworkTime a, NetworkTime b)
{ {
return new NetworkTime(a.TickRate, a.Time + b.Time); return new NetworkTime(a.TickRate, a.Time + b.Time);
} }
/// <summary>
/// Computes the time a number of seconds later
/// </summary>
/// <param name="a">The start time</param>
/// <param name="b">The number of seconds to add</param>
/// <returns>The resulting time</returns>
public static NetworkTime operator +(NetworkTime a, double b) public static NetworkTime operator +(NetworkTime a, double b)
{ {
a.m_TimeSec += b; a.m_TimeSec += b;
@@ -149,6 +172,12 @@ namespace Unity.Netcode
return a; return a;
} }
/// <summary>
/// Computes the time a number of seconds before
/// </summary>
/// <param name="a">The start time</param>
/// <param name="b">The number of seconds to remove</param>
/// <returns>The resulting time</returns>
public static NetworkTime operator -(NetworkTime a, double b) public static NetworkTime operator -(NetworkTime a, double b)
{ {
return a + -b; return a + -b;

View File

@@ -36,12 +36,27 @@ namespace Unity.Netcode
/// Gets or sets the ratio at which the NetworkTimeSystem speeds up or slows down time. /// Gets or sets the ratio at which the NetworkTimeSystem speeds up or slows down time.
/// </summary> /// </summary>
public double AdjustmentRatio { get; set; } public double AdjustmentRatio { get; set; }
/// <summary>
/// The current local time with the local time offset applied
/// </summary>
public double LocalTime => m_TimeSec + m_CurrentLocalTimeOffset; public double LocalTime => m_TimeSec + m_CurrentLocalTimeOffset;
/// <summary>
/// The current server time with the server time offset applied
/// </summary>
public double ServerTime => m_TimeSec + m_CurrentServerTimeOffset; public double ServerTime => m_TimeSec + m_CurrentServerTimeOffset;
internal double LastSyncedServerTimeSec { get; private set; } internal double LastSyncedServerTimeSec { get; private set; }
internal double LastSyncedRttSec { get; private set; } internal double LastSyncedRttSec { get; private set; }
/// <summary>
/// The constructor class for <see cref="NetworkTickSystem"/>
/// </summary>
/// <param name="localBufferSec">The amount of time, in seconds, the server should buffer incoming client messages.</param>
/// <param name="serverBufferSec">The amount of the time in seconds the client should buffer incoming messages from the server.</param>
/// <param name="hardResetThresholdSec">The threshold, in seconds, used to force a hard catchup of network time.</param>
/// <param name="adjustmentRatio">The ratio at which the NetworkTimeSystem speeds up or slows down time.</param>
public NetworkTimeSystem(double localBufferSec, double serverBufferSec, double hardResetThresholdSec, double adjustmentRatio = 0.01d) public NetworkTimeSystem(double localBufferSec, double serverBufferSec, double hardResetThresholdSec, double adjustmentRatio = 0.01d)
{ {
LocalBufferSec = localBufferSec; LocalBufferSec = localBufferSec;

View File

@@ -3,6 +3,11 @@ using UnityEngine;
namespace Unity.Netcode namespace Unity.Netcode
{ {
/// <summary>
/// The generic transport class all Netcode for GameObjects network transport implementations
/// derive from. Use this class to add a custom transport.
/// <seealso cref="Transports.UTP.UnityTransport"> for an example of how a transport is integrated</seealso>
/// </summary>
public abstract class NetworkTransport : MonoBehaviour public abstract class NetworkTransport : MonoBehaviour
{ {
/// <summary> /// <summary>
@@ -45,7 +50,7 @@ namespace Unity.Netcode
} }
/// <summary> /// <summary>
/// Send a payload to the specified clientId, data and channelName. /// Send a payload to the specified clientId, data and networkDelivery.
/// </summary> /// </summary>
/// <param name="clientId">The clientId to send to</param> /// <param name="clientId">The clientId to send to</param>
/// <param name="payload">The data to send</param> /// <param name="payload">The data to send</param>
@@ -64,11 +69,13 @@ namespace Unity.Netcode
/// <summary> /// <summary>
/// Connects client to the server /// Connects client to the server
/// </summary> /// </summary>
/// <returns>Returns success or failure</returns>
public abstract bool StartClient(); public abstract bool StartClient();
/// <summary> /// <summary>
/// Starts to listening for incoming clients /// Starts to listening for incoming clients
/// </summary> /// </summary>
/// <returns>Returns success or failure</returns>
public abstract bool StartServer(); public abstract bool StartServer();
/// <summary> /// <summary>

View File

@@ -1,8 +1,17 @@
namespace Unity.Netcode.Transports.UTP namespace Unity.Netcode.Transports.UTP
{ {
/// <summary>
/// Caching structure to track network metrics related information.
/// </summary>
public struct NetworkMetricsContext public struct NetworkMetricsContext
{ {
/// <summary>
/// The number of packet sent.
/// </summary>
public uint PacketSentCount; public uint PacketSentCount;
/// <summary>
/// The number of packet received.
/// </summary>
public uint PacketReceivedCount; public uint PacketReceivedCount;
} }
} }

View File

@@ -16,6 +16,14 @@ namespace Unity.Netcode.Transports.UTP
/// </summary> /// </summary>
public interface INetworkStreamDriverConstructor public interface INetworkStreamDriverConstructor
{ {
/// <summary>
/// Creates the internal NetworkDriver
/// </summary>
/// <param name="transport">The owner transport</param>
/// <param name="driver">The driver</param>
/// <param name="unreliableFragmentedPipeline">The UnreliableFragmented NetworkPipeline</param>
/// <param name="unreliableSequencedFragmentedPipeline">The UnreliableSequencedFragmented NetworkPipeline</param>
/// <param name="reliableSequencedPipeline">The ReliableSequenced NetworkPipeline</param>
void CreateDriver( void CreateDriver(
UnityTransport transport, UnityTransport transport,
out NetworkDriver driver, out NetworkDriver driver,
@@ -24,6 +32,9 @@ namespace Unity.Netcode.Transports.UTP
out NetworkPipeline reliableSequencedPipeline); out NetworkPipeline reliableSequencedPipeline);
} }
/// <summary>
/// Helper utility class to convert <see cref="Networking.Transport"/> error codes to human readable error messages.
/// </summary>
public static class ErrorUtilities public static class ErrorUtilities
{ {
private const string k_NetworkSuccess = "Success"; private const string k_NetworkSuccess = "Success";
@@ -37,6 +48,12 @@ namespace Unity.Netcode.Transports.UTP
private const string k_NetworkSendHandleInvalid = "Invalid NetworkInterface Send Handle. Likely caused by pipeline send data corruption."; private const string k_NetworkSendHandleInvalid = "Invalid NetworkInterface Send Handle. Likely caused by pipeline send data corruption.";
private const string k_NetworkArgumentMismatch = "Invalid NetworkEndpoint Arguments."; private const string k_NetworkArgumentMismatch = "Invalid NetworkEndpoint Arguments.";
/// <summary>
/// Convert error code to human readable error message.
/// </summary>
/// <param name="error">Status code of the error</param>
/// <param name="connectionId">Subject connection ID of the error</param>
/// <returns>Human readable error message.</returns>
public static string ErrorToString(Networking.Transport.Error.StatusCode error, ulong connectionId) public static string ErrorToString(Networking.Transport.Error.StatusCode error, ulong connectionId)
{ {
switch (error) switch (error)
@@ -67,11 +84,24 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// The Netcode for GameObjects NetworkTransport for UnityTransport.
/// Note: This is highly recommended to use over UNet.
/// </summary>
public partial class UnityTransport : NetworkTransport, INetworkStreamDriverConstructor public partial class UnityTransport : NetworkTransport, INetworkStreamDriverConstructor
{ {
/// <summary>
/// Enum type stating the type of protocol
/// </summary>
public enum ProtocolType public enum ProtocolType
{ {
/// <summary>
/// Unity Transport Protocol
/// </summary>
UnityTransport, UnityTransport,
/// <summary>
/// Unity Transport Protocol over Relay
/// </summary>
RelayUnityTransport, RelayUnityTransport,
} }
@@ -82,15 +112,34 @@ namespace Unity.Netcode.Transports.UTP
Connected, Connected,
} }
/// <summary>
/// The default maximum (receive) packet queue size
/// </summary>
public const int InitialMaxPacketQueueSize = 128; public const int InitialMaxPacketQueueSize = 128;
/// <summary>
/// The default maximum payload size
/// </summary>
public const int InitialMaxPayloadSize = 6 * 1024; public const int InitialMaxPayloadSize = 6 * 1024;
/// <summary>
/// The default maximum send queue size
/// </summary>
public const int InitialMaxSendQueueSize = 16 * InitialMaxPayloadSize; public const int InitialMaxSendQueueSize = 16 * InitialMaxPayloadSize;
private static ConnectionAddressData s_DefaultConnectionAddressData = new ConnectionAddressData { Address = "127.0.0.1", Port = 7777, ServerListenAddress = string.Empty }; private static ConnectionAddressData s_DefaultConnectionAddressData = new ConnectionAddressData { Address = "127.0.0.1", Port = 7777, ServerListenAddress = string.Empty };
#pragma warning disable IDE1006 // Naming Styles #pragma warning disable IDE1006 // Naming Styles
/// <summary>
/// The global <see cref="INetworkStreamDriverConstructor"/> implementation
/// </summary>
public static INetworkStreamDriverConstructor s_DriverConstructor; public static INetworkStreamDriverConstructor s_DriverConstructor;
#pragma warning restore IDE1006 // Naming Styles #pragma warning restore IDE1006 // Naming Styles
/// <summary>
/// Returns either the global <see cref="INetworkStreamDriverConstructor"/> implementation or the current <see cref="UnityTransport"/> instance
/// </summary>
public INetworkStreamDriverConstructor DriverConstructor => s_DriverConstructor ?? this; public INetworkStreamDriverConstructor DriverConstructor => s_DriverConstructor ?? this;
[Tooltip("Which protocol should be selected (Relay/Non-Relay).")] [Tooltip("Which protocol should be selected (Relay/Non-Relay).")]
@@ -187,17 +236,29 @@ namespace Unity.Netcode.Transports.UTP
set => m_DisconnectTimeoutMS = value; set => m_DisconnectTimeoutMS = value;
} }
/// <summary>
/// Structure to store the address to connect to
/// </summary>
[Serializable] [Serializable]
public struct ConnectionAddressData public struct ConnectionAddressData
{ {
/// <summary>
/// IP address of the server (address to which clients will connect to).
/// </summary>
[Tooltip("IP address of the server (address to which clients will connect to).")] [Tooltip("IP address of the server (address to which clients will connect to).")]
[SerializeField] [SerializeField]
public string Address; public string Address;
/// <summary>
/// UDP port of the server.
/// </summary>
[Tooltip("UDP port of the server.")] [Tooltip("UDP port of the server.")]
[SerializeField] [SerializeField]
public ushort Port; public ushort Port;
/// <summary>
/// IP address the server will listen on. If not provided, will use 'Address'.
/// </summary>
[Tooltip("IP address the server will listen on. If not provided, will use 'Address'.")] [Tooltip("IP address the server will listen on. If not provided, will use 'Address'.")]
[SerializeField] [SerializeField]
public string ServerListenAddress; public string ServerListenAddress;
@@ -213,29 +274,58 @@ namespace Unity.Netcode.Transports.UTP
return endpoint; return endpoint;
} }
/// <summary>
/// Endpoint (IP address and port) clients will connect to.
/// </summary>
public NetworkEndPoint ServerEndPoint => ParseNetworkEndpoint(Address, Port); public NetworkEndPoint ServerEndPoint => ParseNetworkEndpoint(Address, Port);
/// <summary>
/// Endpoint (IP address and port) server will listen/bind on.
/// </summary>
public NetworkEndPoint ListenEndPoint => ParseNetworkEndpoint((ServerListenAddress == string.Empty) ? Address : ServerListenAddress, Port); public NetworkEndPoint ListenEndPoint => ParseNetworkEndpoint((ServerListenAddress == string.Empty) ? Address : ServerListenAddress, Port);
} }
/// <summary>
/// The connection (address) data for this <see cref="UnityTransport"/> instance.
/// This is where you can change IP Address, Port, or server's listen address.
/// <see cref="ConnectionAddressData"/>
/// </summary>
public ConnectionAddressData ConnectionData = s_DefaultConnectionAddressData; public ConnectionAddressData ConnectionData = s_DefaultConnectionAddressData;
/// <summary>
/// Parameters for the Network Simulator
/// </summary>
[Serializable] [Serializable]
public struct SimulatorParameters public struct SimulatorParameters
{ {
/// <summary>
/// Delay to add to every send and received packet (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.
/// </summary>
[Tooltip("Delay to add to every send and received packet (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.")] [Tooltip("Delay to add to every send and received packet (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.")]
[SerializeField] [SerializeField]
public int PacketDelayMS; public int PacketDelayMS;
/// <summary>
/// Jitter (random variation) to add/substract to the packet delay (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.
/// </summary>
[Tooltip("Jitter (random variation) to add/substract to the packet delay (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.")] [Tooltip("Jitter (random variation) to add/substract to the packet delay (in milliseconds). Only applies in the editor and in development builds. The value is ignored in production builds.")]
[SerializeField] [SerializeField]
public int PacketJitterMS; public int PacketJitterMS;
/// <summary>
/// Percentage of sent and received packets to drop. Only applies in the editor and in the editor and in developments builds.
/// </summary>
[Tooltip("Percentage of sent and received packets to drop. Only applies in the editor and in the editor and in developments builds.")] [Tooltip("Percentage of sent and received packets to drop. Only applies in the editor and in the editor and in developments builds.")]
[SerializeField] [SerializeField]
public int PacketDropRate; public int PacketDropRate;
} }
/// <summary>
/// Can be used to simulate poor network conditions such as:
/// - packet delay/latency
/// - packet jitter (variances in latency, see: https://en.wikipedia.org/wiki/Jitter)
/// - packet drop rate (packet loss)
/// </summary>
public SimulatorParameters DebugSimulator = new SimulatorParameters public SimulatorParameters DebugSimulator = new SimulatorParameters
{ {
PacketDelayMS = 0, PacketDelayMS = 0,
@@ -261,8 +351,14 @@ namespace Unity.Netcode.Transports.UTP
private NetworkPipeline m_UnreliableSequencedFragmentedPipeline; private NetworkPipeline m_UnreliableSequencedFragmentedPipeline;
private NetworkPipeline m_ReliableSequencedPipeline; private NetworkPipeline m_ReliableSequencedPipeline;
/// <summary>
/// The client id used to represent the server.
/// </summary>
public override ulong ServerClientId => m_ServerClientId; public override ulong ServerClientId => m_ServerClientId;
/// <summary>
/// The current ProtocolType used by the transport
/// </summary>
public ProtocolType Protocol => m_ProtocolType; public ProtocolType Protocol => m_ProtocolType;
private RelayServerData m_RelayServerData; private RelayServerData m_RelayServerData;
@@ -428,6 +524,14 @@ namespace Unity.Netcode.Transports.UTP
m_ProtocolType = inProtocol; m_ProtocolType = inProtocol;
} }
/// <summary>Set the relay server data for the server.</summary>
/// <param name="ipv4Address">IP address of the relay server.</param>
/// <param name="port">UDP port of the relay server.</param>
/// <param name="allocationIdBytes">Allocation ID as a byte array.</param>
/// <param name="keyBytes">Allocation key as a byte array.</param>
/// <param name="connectionDataBytes">Connection data as a byte array.</param>
/// <param name="hostConnectionDataBytes">The HostConnectionData as a byte array.</param>
/// <param name="isSecure">Whether the connection is secure (uses DTLS).</param>
public void SetRelayServerData(string ipv4Address, ushort port, byte[] allocationIdBytes, byte[] keyBytes, byte[] connectionDataBytes, byte[] hostConnectionDataBytes = null, bool isSecure = false) public void SetRelayServerData(string ipv4Address, ushort port, byte[] allocationIdBytes, byte[] keyBytes, byte[] connectionDataBytes, byte[] hostConnectionDataBytes = null, bool isSecure = false)
{ {
RelayConnectionData hostConnectionData; RelayConnectionData hostConnectionData;
@@ -489,6 +593,9 @@ namespace Unity.Netcode.Transports.UTP
/// <summary> /// <summary>
/// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/> /// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/>
/// </summary> /// </summary>
/// <param name="ipv4Address">The remote IP address</param>
/// <param name="port">The remote port</param>
/// <param name="listenAddress">The local listen address</param>
public void SetConnectionData(string ipv4Address, ushort port, string listenAddress = null) public void SetConnectionData(string ipv4Address, ushort port, string listenAddress = null)
{ {
ConnectionData = new ConnectionAddressData ConnectionData = new ConnectionAddressData
@@ -504,6 +611,8 @@ namespace Unity.Netcode.Transports.UTP
/// <summary> /// <summary>
/// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/> /// Sets IP and Port information. This will be ignored if using the Unity Relay and you should call <see cref="SetRelayServerData"/>
/// </summary> /// </summary>
/// <param name="endPoint">The remote end point</param>
/// <param name="listenEndPoint">The local listen endpoint</param>
public void SetConnectionData(NetworkEndPoint endPoint, NetworkEndPoint listenEndPoint = default) public void SetConnectionData(NetworkEndPoint endPoint, NetworkEndPoint listenEndPoint = default)
{ {
string serverAddress = endPoint.Address.Split(':')[0]; string serverAddress = endPoint.Address.Split(':')[0];
@@ -916,6 +1025,9 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// Disconnects the local client from the remote
/// </summary>
public override void DisconnectLocalClient() public override void DisconnectLocalClient()
{ {
if (m_State == State.Connected) if (m_State == State.Connected)
@@ -940,6 +1052,10 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// Disconnects a remote client from the server
/// </summary>
/// <param name="clientId">The client to disconnect</param>
public override void DisconnectRemoteClient(ulong clientId) public override void DisconnectRemoteClient(ulong clientId)
{ {
Debug.Assert(m_State == State.Listening, "DisconnectRemoteClient should be called on a listening server"); Debug.Assert(m_State == State.Listening, "DisconnectRemoteClient should be called on a listening server");
@@ -959,6 +1075,11 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// Gets the current RTT for a specific client
/// </summary>
/// <param name="clientId">The client RTT to get</param>
/// <returns>The RTT</returns>
public override ulong GetCurrentRtt(ulong clientId) public override ulong GetCurrentRtt(ulong clientId)
{ {
// We don't know if this is getting called from inside NGO (which presumably knows to // We don't know if this is getting called from inside NGO (which presumably knows to
@@ -979,6 +1100,10 @@ namespace Unity.Netcode.Transports.UTP
return (ulong)ExtractRtt(ParseClientId(clientId)); return (ulong)ExtractRtt(ParseClientId(clientId));
} }
/// <summary>
/// Initializes the transport
/// </summary>
/// <param name="networkManager">The NetworkManager that initialized and owns the transport</param>
public override void Initialize(NetworkManager networkManager = null) public override void Initialize(NetworkManager networkManager = null)
{ {
Debug.Assert(sizeof(ulong) == UnsafeUtility.SizeOf<NetworkConnection>(), "Netcode connection id size does not match UTP connection id size"); Debug.Assert(sizeof(ulong) == UnsafeUtility.SizeOf<NetworkConnection>(), "Netcode connection id size does not match UTP connection id size");
@@ -1000,6 +1125,13 @@ namespace Unity.Netcode.Transports.UTP
#endif #endif
} }
/// <summary>
/// Polls for incoming events, with an extra output parameter to report the precise time the event was received.
/// </summary>
/// <param name="clientId">The clientId this event is for</param>
/// <param name="payload">The incoming data payload</param>
/// <param name="receiveTime">The time the event was received, as reported by Time.realtimeSinceStartup.</param>
/// <returns>Returns the event type</returns>
public override NetcodeNetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime) public override NetcodeNetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
{ {
clientId = default; clientId = default;
@@ -1008,6 +1140,12 @@ namespace Unity.Netcode.Transports.UTP
return NetcodeNetworkEvent.Nothing; return NetcodeNetworkEvent.Nothing;
} }
/// <summary>
/// Send a payload to the specified clientId, data and networkDelivery.
/// </summary>
/// <param name="clientId">The clientId to send to</param>
/// <param name="payload">The data to send</param>
/// <param name="networkDelivery">The delivery type (QoS) to send data with</param>
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery) public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
{ {
if (payload.Count > m_MaxPayloadSize) if (payload.Count > m_MaxPayloadSize)
@@ -1069,6 +1207,14 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// Connects client to the server
/// Note:
/// When this method returns false it could mean:
/// - You are trying to start a client that is already started
/// - It failed during the initial port binding when attempting to begin to connect
/// </summary>
/// <returns>true if the client was started and false if it failed to start the client</returns>
public override bool StartClient() public override bool StartClient()
{ {
if (m_Driver.IsCreated) if (m_Driver.IsCreated)
@@ -1084,6 +1230,14 @@ namespace Unity.Netcode.Transports.UTP
return succeeded; return succeeded;
} }
/// <summary>
/// Starts to listening for incoming clients
/// Note:
/// When this method returns false it could mean:
/// - You are trying to start a client that is already started
/// - It failed during the initial port binding when attempting to begin to connect
/// </summary>
/// <returns>true if the server was started and false if it failed to start the server</returns>
public override bool StartServer() public override bool StartServer()
{ {
if (m_Driver.IsCreated) if (m_Driver.IsCreated)
@@ -1113,6 +1267,9 @@ namespace Unity.Netcode.Transports.UTP
} }
} }
/// <summary>
/// Shuts down the transport
/// </summary>
public override void Shutdown() public override void Shutdown()
{ {
if (!m_Driver.IsCreated) if (!m_Driver.IsCreated)
@@ -1152,6 +1309,14 @@ namespace Unity.Netcode.Transports.UTP
); );
} }
/// <summary>
/// Creates the internal NetworkDriver
/// </summary>
/// <param name="transport">The owner transport</param>
/// <param name="driver">The driver</param>
/// <param name="unreliableFragmentedPipeline">The UnreliableFragmented NetworkPipeline</param>
/// <param name="unreliableSequencedFragmentedPipeline">The UnreliableSequencedFragmented NetworkPipeline</param>
/// <param name="reliableSequencedPipeline">The ReliableSequenced NetworkPipeline</param>
public void CreateDriver(UnityTransport transport, out NetworkDriver driver, public void CreateDriver(UnityTransport transport, out NetworkDriver driver,
out NetworkPipeline unreliableFragmentedPipeline, out NetworkPipeline unreliableFragmentedPipeline,
out NetworkPipeline unreliableSequencedFragmentedPipeline, out NetworkPipeline unreliableSequencedFragmentedPipeline,

View File

@@ -2,22 +2,22 @@
"name": "com.unity.netcode.gameobjects", "name": "com.unity.netcode.gameobjects",
"displayName": "Netcode for GameObjects", "displayName": "Netcode for GameObjects",
"description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.", "description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.",
"version": "1.0.0-pre.10", "version": "1.0.0",
"unity": "2020.3", "unity": "2020.3",
"dependencies": { "dependencies": {
"com.unity.nuget.mono-cecil": "1.10.1", "com.unity.nuget.mono-cecil": "1.10.1",
"com.unity.transport": "1.1.0" "com.unity.transport": "1.1.0"
}, },
"_upm": { "_upm": {
"changelog": "### Added\n\n- Added a new `OnTransportFailure` callback to `NetworkManager`. This callback is invoked when the manager's `NetworkTransport` encounters an unrecoverable error. Transport failures also cause the `NetworkManager` to shut down. Currently, this is only used by `UnityTransport` to signal a timeout of its connection to the Unity Relay servers. (#1994)\n- Added `NetworkEvent.TransportFailure`, which can be used by implementations of `NetworkTransport` to signal to `NetworkManager` that an unrecoverable error was encountered. (#1994)\n- Added test to ensure a warning occurs when nesting NetworkObjects in a NetworkPrefab (#1969)\n- Added `NetworkManager.RemoveNetworkPrefab(...)` to remove a prefab from the prefabs list (#1950)\n\n### Changed\n\n- Updated `UnityTransport` dependency on `com.unity.transport` to 1.1.0. (#2025)\n- (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972)\n\n### Removed\n\n### Fixed\n- Fixed issue where dynamically spawned `NetworkObject`s could throw an exception if the scene of origin handle was zero (0) and the `NetworkObject` was already spawned. (#2017)\n- Fixed issue where `NetworkObject.Observers` was not being cleared when despawned. (#2009)\n- Fixed `NetworkAnimator` could not run in the server authoritative mode. (#2003)\n- Fixed issue where late joining clients would get a soft synchronization error if any in-scene placed NetworkObjects were parented under another `NetworkObject`. (#1985)\n- Fixed issue where `NetworkBehaviourReference` would throw a type cast exception if using `NetworkBehaviourReference.TryGet` and the component type was not found. (#1984)\n- Fixed `NetworkSceneManager` was not sending scene event notifications for the currently active scene and any additively loaded scenes when loading a new scene in `LoadSceneMode.Single` mode. (#1975)\n- Fixed issue where one or more clients disconnecting during a scene event would cause `LoadEventCompleted` or `UnloadEventCompleted` to wait until the `NetworkConfig.LoadSceneTimeOut` period before being triggered. (#1973)\n- Fixed issues when multiple `ConnectionApprovalCallback`s were registered (#1972)\n- Fixed a regression in serialization support: `FixedString`, `Vector2Int`, and `Vector3Int` types can now be used in NetworkVariables and RPCs again without requiring a `ForceNetworkSerializeByMemcpy<>` wrapper. (#1961)\n- Fixed generic types that inherit from NetworkBehaviour causing crashes at compile time. (#1976)\n- Fixed endless dialog boxes when adding a `NetworkBehaviour` to a `NetworkManager` or vice-versa. (#1947)\n- Fixed `NetworkAnimator` issue where it was only synchronizing parameters if the layer or state changed or was transitioning between states. (#1946)\n- Fixed `NetworkAnimator` issue where when it did detect a parameter had changed it would send all parameters as opposed to only the parameters that changed. (#1946)\n- Fixed `NetworkAnimator` issue where it was not always disposing the `NativeArray` that is allocated when spawned. (#1946)\n- Fixed `NetworkAnimator` issue where it was not taking the animation speed or state speed multiplier into consideration. (#1946)\n- Fixed `NetworkAnimator` issue where it was not properly synchronizing late joining clients if they joined while `Animator` was transitioning between states. (#1946)\n- Fixed `NetworkAnimator` issue where the server was not relaying changes to non-owner clients when a client was the owner. (#1946)\n- Fixed issue where the `PacketLoss` metric for tools would return the packet loss over a connection lifetime instead of a single frame. (#2004)" "changelog": "### Changed\n\n- Changed version to 1.0.0. (#2046)"
}, },
"upmCi": { "upmCi": {
"footprint": "13bd9771fd94050d43c32b238d73617da4b2389d" "footprint": "382d762a40cdcb42ebaf495e373effb00362baf1"
}, },
"repository": { "repository": {
"url": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git", "url": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git",
"type": "git", "type": "git",
"revision": "d1302ce0b946a675f49425dbd11ee2c4afe89d3f" "revision": "fddb7cd920e1db9e49d44846d7121e38f59bd137"
}, },
"samples": [ "samples": [
{ {