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.10.0] - 2024-07-22 ### Added - Added `NetworkBehaviour.OnNetworkPreSpawn` and `NetworkBehaviour.OnNetworkPostSpawn` methods that provide the ability to handle pre and post spawning actions during the `NetworkObject` spawn sequence. (#2906) - Added a client-side only `NetworkBehaviour.OnNetworkSessionSynchronized` convenience method that is invoked on all `NetworkBehaviour`s after a newly joined client has finished synchronizing with the network session in progress. (#2906) - Added `NetworkBehaviour.OnInSceneObjectsSpawned` convenience method that is invoked when all in-scene `NetworkObject`s have been spawned after a scene has been loaded or upon a host or server starting. (#2906) ### Fixed - Fixed issue where the realtime network stats monitor was not able to display RPC traffic in release builds due to those stats being only available in development builds or the editor. (#2980) - Fixed issue where `NetworkManager.ScenesLoaded` was not being updated if `PostSynchronizationSceneUnloading` was set and any loaded scenes not used during synchronization were unloaded.(#2977) - Fixed issue where internal delta serialization could not have a byte serializer defined when serializing deltas for other types. Added `[GenerateSerializationForType(typeof(byte))]` to both the `NetworkVariable` and `AnticipatedNetworkVariable` classes to assure a byte serializer is defined. (#2953) - Fixed issue with the client count not being correct on the host or server side when a client disconnects itself from a session. (#2941) - Fixed issue with the host trying to send itself a message that it has connected when first starting up. (#2941) - Fixed issue where in-scene placed NetworkObjects could be destroyed if a client disconnects early and/or before approval. (#2923) - Fixed issue where `NetworkDeltaPosition` would "jitter" periodically if both unreliable delta state updates and half-floats were used together. (#2922) - Fixed issue where `NetworkRigidbody2D` would not properly change body type based on the instance's authority when spawned. (#2916) - Fixed issue where a `NetworkObject` component's associated `NetworkBehaviour` components would not be detected if scene loading is disabled in the editor and the currently loaded scene has in-scene placed `NetworkObject`s. (#2906) - Fixed issue where an in-scene placed `NetworkObject` with `NetworkTransform` that is also parented under a `GameObject` would not properly synchronize when the parent `GameObject` had a world space position other than 0,0,0. (#2895) ### Changed
222 lines
9.4 KiB
C#
222 lines
9.4 KiB
C#
using System.Runtime.CompilerServices;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.Netcode.Components
|
|
{
|
|
/// <summary>
|
|
/// Used to synchromnize delta position when half float precision is enabled
|
|
/// </summary>
|
|
public struct NetworkDeltaPosition : INetworkSerializable
|
|
{
|
|
internal const float MaxDeltaBeforeAdjustment = 64f;
|
|
|
|
/// <summary>
|
|
/// The HalfVector3 used to synchronize the delta in position
|
|
/// </summary>
|
|
public HalfVector3 HalfVector3;
|
|
|
|
internal Vector3 CurrentBasePosition;
|
|
internal Vector3 PrecisionLossDelta;
|
|
internal Vector3 HalfDeltaConvertedBack;
|
|
internal Vector3 PreviousPosition;
|
|
internal Vector3 DeltaPosition;
|
|
internal int NetworkTick;
|
|
|
|
internal bool SynchronizeBase;
|
|
|
|
internal bool CollapsedDeltaIntoBase;
|
|
|
|
/// <summary>
|
|
/// The serialization implementation of <see cref="INetworkSerializable"/>
|
|
/// </summary>
|
|
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
|
{
|
|
if (!SynchronizeBase)
|
|
{
|
|
HalfVector3.NetworkSerialize(serializer);
|
|
}
|
|
else
|
|
{
|
|
serializer.SerializeValue(ref DeltaPosition);
|
|
serializer.SerializeValue(ref CurrentBasePosition);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the full precision value of Vector3 position while also potentially updating the current base position.
|
|
/// </summary>
|
|
/// <param name="networkTick">Use the current network tick value.</param>
|
|
/// <returns>The full position as a <see cref="Vector3"/>.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public Vector3 ToVector3(int networkTick)
|
|
{
|
|
// When synchronizing, it is possible to have a state update arrive
|
|
// for the same synchronization network tick. Under this scenario,
|
|
// we only want to return the existing CurrentBasePosition + DeltaPosition
|
|
// values and not process the X, Y, or Z values.
|
|
// (See the constructors below)
|
|
if (networkTick == NetworkTick)
|
|
{
|
|
return CurrentBasePosition + DeltaPosition;
|
|
}
|
|
for (int i = 0; i < HalfVector3.Length; i++)
|
|
{
|
|
if (HalfVector3.AxisToSynchronize[i])
|
|
{
|
|
DeltaPosition[i] = Mathf.HalfToFloat(HalfVector3.Axis[i].value);
|
|
// If we exceed or are equal to the maximum delta value then we need to
|
|
// apply the delta to the CurrentBasePosition value and reset the delta
|
|
// position for the axis.
|
|
if (Mathf.Abs(DeltaPosition[i]) >= MaxDeltaBeforeAdjustment)
|
|
{
|
|
CurrentBasePosition[i] += DeltaPosition[i];
|
|
DeltaPosition[i] = 0.0f;
|
|
HalfVector3.Axis[i] = half.zero;
|
|
}
|
|
}
|
|
}
|
|
return CurrentBasePosition + DeltaPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the current base position (excluding the delta position offset).
|
|
/// </summary>
|
|
/// <returns>The current base position as a <see cref="Vector3"/></returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public Vector3 GetCurrentBasePosition()
|
|
{
|
|
return CurrentBasePosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the full position which includes the delta offset position.
|
|
/// </summary>
|
|
/// <returns>The full position as a <see cref="Vector3"/>.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public Vector3 GetFullPosition()
|
|
{
|
|
return CurrentBasePosition + DeltaPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The half float vector3 version of the current delta position.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Only applies to the authoritative side for <see cref="NetworkTransform"/> instances.
|
|
/// </remarks>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public Vector3 GetConvertedDelta()
|
|
{
|
|
return HalfDeltaConvertedBack;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The full precision current delta position.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Authoritative: Will have no precision loss
|
|
/// Non-Authoritative: Has the current network tick's loss of precision.
|
|
/// Precision loss adjustments are one network tick behind on the
|
|
/// non-authoritative side.
|
|
/// </remarks>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public Vector3 GetDeltaPosition()
|
|
{
|
|
return DeltaPosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the position delta based off of the current base position.
|
|
/// </summary>
|
|
/// <param name="vector3">The full precision <see cref="Vector3"/> value to (converted to half floats) used to determine the delta offset positon.</param>
|
|
/// <param name="networkTick">Set the current network tick value when updating.</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void UpdateFrom(ref Vector3 vector3, int networkTick)
|
|
{
|
|
CollapsedDeltaIntoBase = false;
|
|
NetworkTick = networkTick;
|
|
DeltaPosition = (vector3 + PrecisionLossDelta) - CurrentBasePosition;
|
|
for (int i = 0; i < HalfVector3.Length; i++)
|
|
{
|
|
if (HalfVector3.AxisToSynchronize[i])
|
|
{
|
|
HalfVector3.Axis[i] = math.half(DeltaPosition[i]);
|
|
HalfDeltaConvertedBack[i] = Mathf.HalfToFloat(HalfVector3.Axis[i].value);
|
|
PrecisionLossDelta[i] = DeltaPosition[i] - HalfDeltaConvertedBack[i];
|
|
if (Mathf.Abs(HalfDeltaConvertedBack[i]) >= MaxDeltaBeforeAdjustment)
|
|
{
|
|
CurrentBasePosition[i] += HalfDeltaConvertedBack[i];
|
|
HalfDeltaConvertedBack[i] = 0.0f;
|
|
DeltaPosition[i] = 0.0f;
|
|
CollapsedDeltaIntoBase = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < HalfVector3.Length; i++)
|
|
{
|
|
if (HalfVector3.AxisToSynchronize[i])
|
|
{
|
|
PreviousPosition[i] = vector3[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="vector3">The initial axial values (converted to half floats) when instantiated.</param>
|
|
/// <param name="networkTick">Set the network tick value to the current network tick when instantiating.</param>
|
|
/// <param name="axisToSynchronize">The axis to be synchronized.</param>
|
|
public NetworkDeltaPosition(Vector3 vector3, int networkTick, bool3 axisToSynchronize)
|
|
{
|
|
NetworkTick = networkTick;
|
|
CurrentBasePosition = vector3;
|
|
PreviousPosition = vector3;
|
|
PrecisionLossDelta = Vector3.zero;
|
|
DeltaPosition = Vector3.zero;
|
|
HalfDeltaConvertedBack = Vector3.zero;
|
|
HalfVector3 = new HalfVector3(vector3, axisToSynchronize);
|
|
SynchronizeBase = false;
|
|
CollapsedDeltaIntoBase = false;
|
|
UpdateFrom(ref vector3, networkTick);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor that defaults to all axis being synchronized.
|
|
/// </summary>
|
|
/// <param name="vector3">The initial axial values (converted to half floats) when instantiated.</param>
|
|
/// <param name="networkTick">Set the network tick value to the current network tick when instantiating.</param>
|
|
public NetworkDeltaPosition(Vector3 vector3, int networkTick) : this(vector3, networkTick, math.bool3(true))
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="x">The initial x axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="y">The initial y axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="z">The initial z axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="networkTick">Set the network tick value to the current network tick when instantiating.</param>
|
|
/// <param name="axisToSynchronize">The axis to be synchronized.</param>
|
|
public NetworkDeltaPosition(float x, float y, float z, int networkTick, bool3 axisToSynchronize) :
|
|
this(new Vector3(x, y, z), networkTick, axisToSynchronize)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="x">The initial x axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="y">The initial y axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="z">The initial z axis (converted to half float) value when instantiated.</param>
|
|
/// <param name="networkTick">Set the network tick value to the current network tick when instantiating.</param>
|
|
public NetworkDeltaPosition(float x, float y, float z, int networkTick) :
|
|
this(new Vector3(x, y, z), networkTick, math.bool3(true))
|
|
{
|
|
}
|
|
}
|
|
}
|