diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md
index 3353565e01..7105c92dc8 100644
--- a/com.unity.netcode.gameobjects/CHANGELOG.md
+++ b/com.unity.netcode.gameobjects/CHANGELOG.md
@@ -17,6 +17,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Changed
+- Improve performance of `NetworkTransformState`. (#3770)
+
### Deprecated
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
index eb2abeb288..ce277533c7 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/AnticipatedNetworkTransform.cs
@@ -86,8 +86,6 @@ public struct TransformState
private bool m_OutstandingAuthorityChange = false;
- private NetworkManager m_NetworkManager;
-
#if UNITY_EDITOR
private void Reset()
{
@@ -159,7 +157,7 @@ public bool ShouldReanticipate
/// The anticipated position
public void AnticipateMove(Vector3 newPosition)
{
- if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening)
+ if (m_CachedNetworkManager == null || m_CachedNetworkManager.ShutdownInProgress || !m_CachedNetworkManager.IsListening)
{
return;
}
@@ -172,7 +170,7 @@ public void AnticipateMove(Vector3 newPosition)
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
- m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter;
+ m_LastAnticipaionCounter = m_CachedNetworkManager.AnticipationSystem.AnticipationCounter;
m_SmoothDuration = 0;
m_CurrentSmoothTime = 0;
@@ -185,7 +183,7 @@ public void AnticipateMove(Vector3 newPosition)
/// The anticipated rotation
public void AnticipateRotate(Quaternion newRotation)
{
- if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening)
+ if (m_CachedNetworkManager == null || m_CachedNetworkManager.ShutdownInProgress || !m_CachedNetworkManager.IsListening)
{
return;
}
@@ -198,7 +196,7 @@ public void AnticipateRotate(Quaternion newRotation)
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
- m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter;
+ m_LastAnticipaionCounter = m_CachedNetworkManager.AnticipationSystem.AnticipationCounter;
m_SmoothDuration = 0;
m_CurrentSmoothTime = 0;
@@ -211,7 +209,7 @@ public void AnticipateRotate(Quaternion newRotation)
/// The anticipated scale
public void AnticipateScale(Vector3 newScale)
{
- if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening)
+ if (m_CachedNetworkManager == null || m_CachedNetworkManager.ShutdownInProgress || !m_CachedNetworkManager.IsListening)
{
return;
}
@@ -224,7 +222,7 @@ public void AnticipateScale(Vector3 newScale)
m_PreviousAnticipatedTransform = m_AnticipatedTransform;
- m_LastAnticipaionCounter = m_NetworkManager.AnticipationSystem.AnticipationCounter;
+ m_LastAnticipaionCounter = m_CachedNetworkManager.AnticipationSystem.AnticipationCounter;
m_SmoothDuration = 0;
m_CurrentSmoothTime = 0;
@@ -237,7 +235,7 @@ public void AnticipateScale(Vector3 newScale)
/// The anticipated transform state
public void AnticipateState(TransformState newState)
{
- if (m_NetworkManager == null || m_NetworkManager.ShutdownInProgress || !m_NetworkManager.IsListening)
+ if (m_CachedNetworkManager == null || m_CachedNetworkManager.ShutdownInProgress || !m_CachedNetworkManager.IsListening)
{
return;
}
@@ -266,7 +264,7 @@ private void ProcessSmoothing()
if (m_CurrentSmoothTime < m_SmoothDuration)
{
- m_CurrentSmoothTime += m_NetworkManager.RealTimeProvider.DeltaTime;
+ m_CurrentSmoothTime += m_CachedNetworkManager.RealTimeProvider.DeltaTime;
var transform_ = transform;
var pct = math.min(m_CurrentSmoothTime / m_SmoothDuration, 1f);
@@ -399,8 +397,8 @@ protected internal override void InternalOnNetworkSessionSynchronized()
ResetAnticipatedState();
m_AnticipatedObject = new AnticipatedObject { Transform = this };
- m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
}
}
@@ -412,23 +410,23 @@ protected internal override void InternalOnNetworkSessionSynchronized()
protected internal override void InternalOnNetworkPostSpawn()
{
base.InternalOnNetworkPostSpawn();
- if (!CanCommitToTransform && m_NetworkManager.IsConnectedClient && !SynchronizeState.IsSynchronizing)
+ if (!CanCommitToTransform && m_CachedNetworkManager.IsConnectedClient && !SynchronizeState.IsSynchronizing)
{
m_OutstandingAuthorityChange = true;
ApplyAuthoritativeState();
ResetAnticipatedState();
m_AnticipatedObject = new AnticipatedObject { Transform = this };
- m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
}
}
///
public override void OnNetworkSpawn()
{
- m_NetworkManager = NetworkManager;
+ m_CachedNetworkManager = NetworkManager;
- if (m_NetworkManager.DistributedAuthorityMode)
+ if (m_CachedNetworkManager.DistributedAuthorityMode)
{
Debug.LogWarning($"This component is not currently supported in distributed authority.");
}
@@ -445,8 +443,8 @@ public override void OnNetworkSpawn()
ResetAnticipatedState();
m_AnticipatedObject = new AnticipatedObject { Transform = this };
- m_NetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.RegisterForAnticipationEvents(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.AllAnticipatedObjects.Add(m_AnticipatedObject);
}
///
@@ -454,9 +452,9 @@ public override void OnNetworkDespawn()
{
if (m_AnticipatedObject != null)
{
- m_NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject);
m_AnticipatedObject = null;
}
ResetAnticipatedState();
@@ -469,9 +467,9 @@ public override void OnDestroy()
{
if (m_AnticipatedObject != null)
{
- m_NetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject);
- m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.DeregisterForAnticipationEvents(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.AllAnticipatedObjects.Remove(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.ObjectsToReanticipate.Remove(m_AnticipatedObject);
m_AnticipatedObject = null;
}
@@ -518,7 +516,7 @@ public void Smooth(TransformState from, TransformState to, float durationSeconds
protected override void OnBeforeUpdateTransformState()
{
// this is called when new data comes from the server
- m_LastAuthorityUpdateCounter = m_NetworkManager.AnticipationSystem.LastAnticipationAck;
+ m_LastAuthorityUpdateCounter = m_CachedNetworkManager.AnticipationSystem.LastAnticipationAck;
m_OutstandingAuthorityChange = true;
}
@@ -571,7 +569,7 @@ protected override void OnTransformUpdated()
m_AnticipatedTransform = m_AuthoritativeTransform;
ShouldReanticipate = true;
- m_NetworkManager.AnticipationSystem.ObjectsToReanticipate.Add(m_AnticipatedObject);
+ m_CachedNetworkManager.AnticipationSystem.ObjectsToReanticipate.Add(m_AnticipatedObject);
}
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
index 6162ad91e2..c38579c0a6 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs
@@ -26,11 +26,23 @@ public class NetworkTransform : NetworkBehaviour
internal bool NetworkTransformExpanded;
#endif
+ internal enum Axis { X, Y, Z }
+
+ internal enum AxialType
+ {
+ Position,
+ Rotation,
+ Scale
+ }
#region NETWORK TRANSFORM STATE
+
///
- /// Data structure used to synchronize the
+ /// Any public facing bool value is
+ /// represented in this struct.
+ /// This is what is used internally to get and set the current state's
+ /// public flags/bools.
///
- public struct NetworkTransformState : INetworkSerializable
+ internal struct FlagStates
{
// Persists between state updates (authority dictates if this is set)
private const int k_InLocalSpaceBit = 0x00000001;
@@ -61,18 +73,229 @@ public struct NetworkTransformState : INetworkSerializable
private const int k_ReliableSequenced = 0x00080000;
private const int k_UseUnreliableDeltas = 0x00100000;
private const int k_UnreliableFrameSync = 0x00200000;
- private const int k_SwitchTransformSpaceWhenParented = 0x0400000;
+ private const int k_SwitchTransformSpaceWhenParented = 0x00400000;
+
// (Internal Debugging) When set each state update will contain a state identifier
private const int k_TrackStateId = 0x10000000;
- // Stores persistent and state relative flags
- private uint m_Bitset;
- internal uint BitSet
+ internal bool InLocalSpace;
+ internal bool HasPositionX;
+ internal bool HasPositionY;
+ internal bool HasPositionZ;
+ internal bool HasPositionChange;
+ internal bool HasRotAngleX;
+ internal bool HasRotAngleY;
+ internal bool HasRotAngleZ;
+ internal bool HasRotAngleChange;
+ internal bool HasScaleX;
+ internal bool HasScaleY;
+ internal bool HasScaleZ;
+ internal bool HasScaleChange;
+ internal bool IsTeleportingNextFrame;
+ internal bool WasTeleported;
+ internal bool UseInterpolation;
+ internal bool QuaternionSync;
+ internal bool QuaternionCompression;
+ internal bool UseHalfFloatPrecision;
+ internal bool IsSynchronizing;
+ internal bool UsePositionSlerp;
+ internal bool IsParented;
+ internal bool SynchronizeBaseHalfFloat;
+ internal bool ReliableSequenced;
+ internal bool UseUnreliableDeltas;
+ internal bool UnreliableFrameSync;
+ ///
+ /// When set, non-authority instances will smoothly transition between
+ /// world and local space.
+ ///
+ ///
+ internal bool SwitchTransformSpaceWhenParented;
+ internal bool TrackByStateId;
+ // Authoritative and non-authoritative sides use this to determine if a NetworkTransformState is
+ // dirty or not.
+ internal bool IsDirty;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void MarkChanged(AxialType axialType, bool changed)
+ {
+ switch (axialType)
+ {
+ case AxialType.Position:
+ HasPositionX = changed;
+ HasPositionY = changed;
+ HasPositionZ = changed;
+ HasPositionChange = changed;
+ break;
+ case AxialType.Rotation:
+ HasRotAngleX = changed;
+ HasRotAngleY = changed;
+ HasRotAngleZ = changed;
+ HasRotAngleChange = changed;
+ break;
+ case AxialType.Scale:
+ HasScaleX = changed;
+ HasScaleY = changed;
+ HasScaleZ = changed;
+ HasScaleChange = changed;
+ break;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetHasPosition(Axis axis, bool changed)
+ {
+ switch (axis)
+ {
+ case Axis.X:
+ HasPositionX = changed;
+ break;
+ case Axis.Y:
+ HasPositionY = changed;
+ break;
+ case Axis.Z:
+ HasPositionZ = changed;
+ break;
+ }
+ HasPositionChange = HasPositionX || HasPositionY || HasPositionZ;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetHasRotation(Axis axis, bool changed)
+ {
+ switch (axis)
+ {
+ case Axis.X:
+ HasRotAngleX = changed;
+ break;
+ case Axis.Y:
+ HasRotAngleY = changed;
+ break;
+ case Axis.Z:
+ HasRotAngleZ = changed;
+ break;
+ }
+ HasRotAngleChange = HasRotAngleX || HasRotAngleY || HasRotAngleZ;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetHasScale(Axis axis, bool changed)
{
- get { return m_Bitset; }
- set { m_Bitset = value; }
+ switch (axis)
+ {
+ case Axis.X:
+ HasScaleX = changed;
+ break;
+ case Axis.Y:
+ HasScaleY = changed;
+ break;
+ case Axis.Z:
+ HasScaleZ = changed;
+ break;
+ }
+ HasScaleChange = HasScaleX || HasScaleY || HasScaleZ;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool HasScale(Axis axis)
+ {
+ return axis == Axis.X ? HasScaleX : axis == Axis.Y ? HasScaleY : HasScaleZ;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal uint GetFlags()
+ {
+ uint bitset = 0;
+ if (InLocalSpace) { bitset |= k_InLocalSpaceBit; }
+ if (HasPositionX) { bitset |= k_PositionXBit; }
+ if (HasPositionY) { bitset |= k_PositionYBit; }
+ if (HasPositionZ) { bitset |= k_PositionZBit; }
+ if (HasRotAngleX) { bitset |= k_RotAngleXBit; }
+ if (HasRotAngleY) { bitset |= k_RotAngleYBit; }
+ if (HasRotAngleZ) { bitset |= k_RotAngleZBit; }
+ if (HasScaleX) { bitset |= k_ScaleXBit; }
+ if (HasScaleY) { bitset |= k_ScaleYBit; }
+ if (HasScaleZ) { bitset |= k_ScaleZBit; }
+ if (IsTeleportingNextFrame) { bitset |= k_TeleportingBit; }
+ if (UseInterpolation) { bitset |= k_Interpolate; }
+ if (QuaternionSync) { bitset |= k_QuaternionSync; }
+ if (QuaternionCompression) { bitset |= k_QuaternionCompress; }
+ if (UseHalfFloatPrecision) { bitset |= k_UseHalfFloats; }
+ if (IsSynchronizing) { bitset |= k_Synchronization; }
+ if (UsePositionSlerp) { bitset |= k_PositionSlerp; }
+ if (IsParented) { bitset |= k_IsParented; }
+ if (SynchronizeBaseHalfFloat) { bitset |= k_SynchBaseHalfFloat; }
+ if (ReliableSequenced) { bitset |= k_ReliableSequenced; }
+ if (UseUnreliableDeltas) { bitset |= k_UseUnreliableDeltas; }
+ if (UnreliableFrameSync) { bitset |= k_UnreliableFrameSync; }
+ if (SwitchTransformSpaceWhenParented) { bitset |= k_SwitchTransformSpaceWhenParented; }
+ if (TrackByStateId) { bitset |= k_TrackStateId; }
+ return bitset;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void SetFlags(uint bitset)
+ {
+ InLocalSpace = (bitset & k_InLocalSpaceBit) != 0;
+ SetHasPosition(Axis.X, (bitset & k_PositionXBit) != 0);
+ SetHasPosition(Axis.Y, (bitset & k_PositionYBit) != 0);
+ SetHasPosition(Axis.Z, (bitset & k_PositionZBit) != 0);
+ SetHasRotation(Axis.X, (bitset & k_RotAngleXBit) != 0);
+ SetHasRotation(Axis.Y, (bitset & k_RotAngleYBit) != 0);
+ SetHasRotation(Axis.Z, (bitset & k_RotAngleZBit) != 0);
+ SetHasScale(Axis.X, (bitset & k_ScaleXBit) != 0);
+ SetHasScale(Axis.Y, (bitset & k_ScaleYBit) != 0);
+ SetHasScale(Axis.Z, (bitset & k_ScaleZBit) != 0);
+ IsTeleportingNextFrame = (bitset & k_TeleportingBit) != 0;
+ UseInterpolation = (bitset & k_Interpolate) != 0;
+ QuaternionSync = (bitset & k_QuaternionSync) != 0;
+ QuaternionCompression = (bitset & k_QuaternionCompress) != 0;
+ UseHalfFloatPrecision = (bitset & k_UseHalfFloats) != 0;
+ IsSynchronizing = (bitset & k_Synchronization) != 0;
+ UsePositionSlerp = (bitset & k_PositionSlerp) != 0;
+ IsParented = (bitset & k_IsParented) != 0;
+ SynchronizeBaseHalfFloat = (bitset & k_SynchBaseHalfFloat) != 0;
+ ReliableSequenced = (bitset & k_ReliableSequenced) != 0;
+ UseUnreliableDeltas = (bitset & k_UseUnreliableDeltas) != 0;
+ UnreliableFrameSync = (bitset & k_UnreliableFrameSync) != 0;
+ SwitchTransformSpaceWhenParented = (bitset & k_SwitchTransformSpaceWhenParented) != 0;
+ TrackByStateId = (bitset & k_TrackStateId) != 0;
+ }
+
+ ///
+ /// Clear everything but flags that should persist between state updates until changed by authority.
+ /// Persistent (non-cleared) flags are , , , ,
+ /// , ,
+ ///
+ internal void ClearBitSetForNextTick()
+ {
+ HasPositionX = false;
+ HasPositionY = false;
+ HasPositionZ = false;
+ HasPositionChange = false;
+ HasRotAngleX = false;
+ HasRotAngleY = false;
+ HasRotAngleZ = false;
+ HasRotAngleChange = false;
+ HasScaleX = false;
+ HasScaleY = false;
+ HasScaleZ = false;
+ HasScaleChange = false;
+ IsTeleportingNextFrame = false;
+ IsSynchronizing = false;
+ IsParented = false;
+ SynchronizeBaseHalfFloat = false;
+ ReliableSequenced = false;
+ UnreliableFrameSync = false;
+ TrackByStateId = false;
+ IsDirty = false;
+ }
+ }
+
+ ///
+ /// Data structure used to synchronize the
+ ///
+ public struct NetworkTransformState : INetworkSerializable
+ {
// Used to store the tick calculated sent time
internal double SentTime;
@@ -104,10 +327,6 @@ internal uint BitSet
// Used to store a compressed quaternion
internal uint QuaternionCompressed;
- // Authoritative and non-authoritative sides use this to determine if a NetworkTransformState is
- // dirty or not.
- internal bool IsDirty { get; set; }
-
///
/// The last byte size of the updated.
///
@@ -126,30 +345,15 @@ internal uint BitSet
private FastBufferReader m_Reader;
private FastBufferWriter m_Writer;
- ///
- /// When set, non-authority instances will smoothly transition between
- /// world and local space.
- ///
- ///
- internal bool SwitchTransformSpaceWhenParented
- {
- get => GetFlag(k_SwitchTransformSpaceWhenParented);
- set
- {
- SetFlag(value, k_SwitchTransformSpaceWhenParented);
- }
- }
+ internal FlagStates FlagStates;
///
/// When set, the is operates in local space
///
public bool InLocalSpace
{
- get => GetFlag(k_InLocalSpaceBit);
- internal set
- {
- SetFlag(value, k_InLocalSpaceBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.InLocalSpace; }
}
// Position
@@ -158,11 +362,8 @@ internal set
///
public bool HasPositionX
{
- get => GetFlag(k_PositionXBit);
- internal set
- {
- SetFlag(value, k_PositionXBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasPositionX; }
}
///
@@ -170,11 +371,8 @@ internal set
///
public bool HasPositionY
{
- get => GetFlag(k_PositionYBit);
- internal set
- {
- SetFlag(value, k_PositionYBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasPositionY; }
}
///
@@ -182,11 +380,8 @@ internal set
///
public bool HasPositionZ
{
- get => GetFlag(k_PositionZBit);
- internal set
- {
- SetFlag(value, k_PositionZBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasPositionZ; }
}
///
@@ -194,10 +389,8 @@ internal set
///
public bool HasPositionChange
{
- get
- {
- return HasPositionX || HasPositionY || HasPositionZ;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasPositionChange; }
}
// RotAngles
@@ -209,11 +402,8 @@ public bool HasPositionChange
///
public bool HasRotAngleX
{
- get => GetFlag(k_RotAngleXBit);
- internal set
- {
- SetFlag(value, k_RotAngleXBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasRotAngleX; }
}
///
@@ -224,11 +414,8 @@ internal set
///
public bool HasRotAngleY
{
- get => GetFlag(k_RotAngleYBit);
- internal set
- {
- SetFlag(value, k_RotAngleYBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasRotAngleY; }
}
///
@@ -239,11 +426,8 @@ internal set
///
public bool HasRotAngleZ
{
- get => GetFlag(k_RotAngleZBit);
- internal set
- {
- SetFlag(value, k_RotAngleZBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasRotAngleZ; }
}
///
@@ -254,22 +438,8 @@ internal set
///
public bool HasRotAngleChange
{
- get
- {
- return HasRotAngleX || HasRotAngleY || HasRotAngleZ;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal bool HasScale(int axisIndex)
- {
- return GetFlag(k_ScaleXBit << axisIndex);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void SetHasScale(int axisIndex, bool isSet)
- {
- SetFlag(isSet, k_ScaleXBit << axisIndex);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasRotAngleChange; }
}
// Scale
@@ -278,11 +448,8 @@ internal void SetHasScale(int axisIndex, bool isSet)
///
public bool HasScaleX
{
- get => GetFlag(k_ScaleXBit);
- internal set
- {
- SetFlag(value, k_ScaleXBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasScaleX; }
}
///
@@ -290,11 +457,8 @@ internal set
///
public bool HasScaleY
{
- get => GetFlag(k_ScaleYBit);
- internal set
- {
- SetFlag(value, k_ScaleYBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasScaleY; }
}
///
@@ -302,11 +466,8 @@ internal set
///
public bool HasScaleZ
{
- get => GetFlag(k_ScaleZBit);
- internal set
- {
- SetFlag(value, k_ScaleZBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasScaleZ; }
}
///
@@ -314,10 +475,8 @@ internal set
///
public bool HasScaleChange
{
- get
- {
- return HasScaleX || HasScaleY || HasScaleZ;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.HasScaleChange; }
}
///
@@ -331,11 +490,8 @@ public bool HasScaleChange
///
public bool IsTeleportingNextFrame
{
- get => GetFlag(k_TeleportingBit);
- internal set
- {
- SetFlag(value, k_TeleportingBit);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.IsTeleportingNextFrame; }
}
///
@@ -344,7 +500,11 @@ internal set
///
/// Note that will be reset in the event you need to do multiple teleports spread out accoss multiple ticks.
///
- public bool WasTeleported { get; internal set; }
+ public bool WasTeleported
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.WasTeleported; }
+ }
///
/// When set the is uses interpolation.
@@ -355,11 +515,8 @@ internal set
///
public bool UseInterpolation
{
- get => GetFlag(k_Interpolate);
- internal set
- {
- SetFlag(value, k_Interpolate);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.UseInterpolation; }
}
///
@@ -372,11 +529,8 @@ internal set
///
public bool QuaternionSync
{
- get => GetFlag(k_QuaternionSync);
- internal set
- {
- SetFlag(value, k_QuaternionSync);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.QuaternionSync; }
}
///
@@ -390,11 +544,8 @@ internal set
///
public bool QuaternionCompression
{
- get => GetFlag(k_QuaternionCompress);
- internal set
- {
- SetFlag(value, k_QuaternionCompress);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.QuaternionCompression; }
}
///
@@ -406,11 +557,8 @@ internal set
///
public bool UseHalfFloatPrecision
{
- get => GetFlag(k_UseHalfFloats);
- internal set
- {
- SetFlag(value, k_UseHalfFloats);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.UseHalfFloatPrecision; }
}
///
@@ -419,11 +567,8 @@ internal set
///
public bool IsSynchronizing
{
- get => GetFlag(k_Synchronization);
- internal set
- {
- SetFlag(value, k_Synchronization);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.IsSynchronizing; }
}
///
@@ -432,11 +577,8 @@ internal set
///
public bool UsePositionSlerp
{
- get => GetFlag(k_PositionSlerp);
- internal set
- {
- SetFlag(value, k_PositionSlerp);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get { return FlagStates.UsePositionSlerp; }
}
///
@@ -447,94 +589,17 @@ internal set
/// true or false as to whether this state update was an unreliable frame synchronization.
public bool IsUnreliableFrameSync()
{
- return UnreliableFrameSync;
+ return FlagStates.UnreliableFrameSync;
}
///
/// Returns true if this state was sent with reliable delivery.
/// If false, then it was sent with unreliable delivery.
///
- ///
- /// Unreliable delivery will only be used if is set.
- ///
/// true or false as to whether this state update was sent with reliable delivery.
public bool IsReliableStateUpdate()
{
- return ReliableSequenced;
- }
-
- internal bool IsParented
- {
- get => GetFlag(k_IsParented);
- set
- {
- SetFlag(value, k_IsParented);
- }
- }
-
- internal bool SynchronizeBaseHalfFloat
- {
- get => GetFlag(k_SynchBaseHalfFloat);
- set
- {
- SetFlag(value, k_SynchBaseHalfFloat);
- }
- }
-
- internal bool ReliableSequenced
- {
- get => GetFlag(k_ReliableSequenced);
- set
- {
- SetFlag(value, k_ReliableSequenced);
- }
- }
-
- internal bool UseUnreliableDeltas
- {
- get => GetFlag(k_UseUnreliableDeltas);
- set
- {
- SetFlag(value, k_UseUnreliableDeltas);
- }
- }
-
- internal bool UnreliableFrameSync
- {
- get => GetFlag(k_UnreliableFrameSync);
- set
- {
- SetFlag(value, k_UnreliableFrameSync);
- }
- }
-
- internal bool TrackByStateId
- {
- get => GetFlag(k_TrackStateId);
- set
- {
- SetFlag(value, k_TrackStateId);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool GetFlag(int flag)
- {
- return (m_Bitset & flag) != 0;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void SetFlag(bool set, int flag)
- {
- if (set) { m_Bitset = m_Bitset | (uint)flag; }
- else { m_Bitset = m_Bitset & (uint)~flag; }
- }
-
- internal void ClearBitSetForNextTick()
- {
- // Clear everything but flags that should persist between state updates until changed by authority
- m_Bitset &= k_InLocalSpaceBit | k_Interpolate | k_UseHalfFloats | k_QuaternionSync | k_QuaternionCompress | k_PositionSlerp | k_UseUnreliableDeltas | k_SwitchTransformSpaceWhenParented;
- IsDirty = false;
+ return FlagStates.ReliableSequenced;
}
///
@@ -669,32 +734,39 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
{
if (isWriting)
{
- if (UseUnreliableDeltas)
+ if (FlagStates.UseUnreliableDeltas)
{
// If teleporting, synchronizing, doing an axial frame sync, or using half float precision and we collapsed a delta into the base position
- if (IsTeleportingNextFrame || IsSynchronizing || UnreliableFrameSync || (UseHalfFloatPrecision && NetworkDeltaPosition.CollapsedDeltaIntoBase))
+ if (FlagStates.IsTeleportingNextFrame || FlagStates.IsSynchronizing || FlagStates.UnreliableFrameSync
+ || (FlagStates.UseHalfFloatPrecision && NetworkDeltaPosition.CollapsedDeltaIntoBase))
{
// Send the message reliably
- ReliableSequenced = true;
+ FlagStates.ReliableSequenced = true;
}
else
{
- ReliableSequenced = false;
+ FlagStates.ReliableSequenced = false;
}
}
else // If not using UseUnreliableDeltas, then always use reliable fragmented sequenced
{
- ReliableSequenced = true;
+ FlagStates.ReliableSequenced = true;
}
- BytePacker.WriteValueBitPacked(m_Writer, m_Bitset);
+ // Serialize the flags as an unsigned int
+ BytePacker.WriteValueBitPacked(m_Writer, FlagStates.GetFlags());
+
// We use network ticks as opposed to absolute time as the authoritative
// side updates on every new tick.
BytePacker.WriteValueBitPacked(m_Writer, NetworkTick);
}
else
{
- ByteUnpacker.ReadValueBitPacked(m_Reader, out m_Bitset);
+ // Deserialize the flags
+ ByteUnpacker.ReadValueBitPacked(m_Reader, out uint bitset);
+ // Set the flags
+ FlagStates.SetFlags(bitset);
+
// We use network ticks as opposed to absolute time as the authoritative
// side updates on every new tick.
ByteUnpacker.ReadValueBitPacked(m_Reader, out NetworkTick);
@@ -710,7 +782,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
#endif
// If debugging states and track by state identifier is enabled, serialize the current state identifier
- if (TrackByStateId)
+ if (FlagStates.TrackByStateId)
{
serializer.SerializeValue(ref StateId);
}
@@ -720,7 +792,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
{
if (UseHalfFloatPrecision)
{
- NetworkDeltaPosition.SynchronizeBase = SynchronizeBaseHalfFloat;
+ NetworkDeltaPosition.SynchronizeBase = FlagStates.SynchronizeBaseHalfFloat;
// Apply which axis should be updated for both write/read (teleporting, synchronizing, or just updating)
NetworkDeltaPosition.HalfVector3.AxisToSynchronize[0] = HasPositionX;
@@ -909,7 +981,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
{
// If we are teleporting (which includes synchronizing) and the associated NetworkObject has a parent
// then we want to serialize the LossyScale since NetworkObject spawn order is not guaranteed
- if (IsTeleportingNextFrame && IsParented)
+ if (IsTeleportingNextFrame && FlagStates.IsParented)
{
serializer.SerializeValue(ref LossyScale);
}
@@ -986,7 +1058,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
if (!isWriting)
{
// Go ahead and mark the local state dirty
- IsDirty = HasPositionChange || HasRotAngleChange || HasScaleChange;
+ FlagStates.IsDirty = HasPositionChange || HasRotAngleChange || HasScaleChange;
LastSerializedSize = m_Reader.Position - positionStart;
}
else
@@ -997,6 +1069,7 @@ public void NetworkSerialize(BufferSerializer serializer) where T : IReade
#endif
}
}
+
}
#endregion
@@ -1600,7 +1673,7 @@ public Vector3 GetSpaceRelativePosition(bool getCurrentState = false)
{
if (!getCurrentState || CanCommitToTransform)
{
- return InLocalSpace ? transform.localPosition : transform.position;
+ return InLocalSpace ? CachedTransform.localPosition : CachedTransform.position;
}
else
{
@@ -1649,7 +1722,7 @@ public Quaternion GetSpaceRelativeRotation(bool getCurrentState = false)
{
if (!getCurrentState || CanCommitToTransform)
{
- return InLocalSpace ? transform.localRotation : transform.rotation;
+ return InLocalSpace ? CachedTransform.localRotation : CachedTransform.rotation;
}
else
{
@@ -1680,7 +1753,7 @@ public Vector3 GetScale(bool getCurrentState = false)
{
if (!getCurrentState || CanCommitToTransform)
{
- return transform.localScale;
+ return CachedTransform.localScale;
}
else
{
@@ -1833,11 +1906,10 @@ protected override void OnSynchronize(ref BufferSerializer serializer)
if (serializer.IsWriter)
{
- SynchronizeState.IsTeleportingNextFrame = true;
- var transformToCommit = transform;
+ SynchronizeState.FlagStates.IsTeleportingNextFrame = true;
// If we are using Half Float Precision, then we want to only synchronize the authority's m_HalfPositionState.FullPosition in order for
// for the non-authority side to be able to properly synchronize delta position updates.
- CheckForStateChange(ref SynchronizeState, ref transformToCommit, true, targetClientId);
+ CheckForStateChange(ref SynchronizeState, true, targetClientId);
SynchronizeState.NetworkSerialize(serializer);
LastTickSync = SynchronizeState.GetNetworkTick();
OnAuthorityPushTransformState(ref SynchronizeState);
@@ -1866,9 +1938,9 @@ private void ApplySynchronization()
// Teleport/Fully Initialize based on the state
ApplyTeleportingState(SynchronizeState);
m_LocalAuthoritativeNetworkState = SynchronizeState;
- m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = false;
- m_LocalAuthoritativeNetworkState.IsSynchronizing = false;
- SynchronizeState.IsSynchronizing = false;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsTeleportingNextFrame = false;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsSynchronizing = false;
+ SynchronizeState.FlagStates.IsSynchronizing = false;
}
#endregion
@@ -1902,7 +1974,7 @@ internal void TryCommitTransformToServer(Transform transformToCommit, double dir
// If we are authority, update the authoritative state
if (CanCommitToTransform)
{
- OnUpdateAuthoritativeState(ref transformToCommit);
+ OnUpdateAuthoritativeState();
}
else // Non-Authority
{
@@ -1942,7 +2014,7 @@ protected virtual void OnAuthorityPushTransformState(ref NetworkTransformState n
/// If there are any transform delta states, this method will synchronize the
/// state with all non-authority instances.
///
- private void TryCommitTransform(ref Transform transformToCommit, bool synchronize = false, bool settingState = false)
+ private void TryCommitTransform(bool synchronize = false, bool settingState = false)
{
// Only the server or the owner is allowed to commit a transform
if (!IsServer && !IsOwner)
@@ -1959,7 +2031,7 @@ private void TryCommitTransform(ref Transform transformToCommit, bool synchroniz
}
#endif
// If the transform has deltas (returns dirty) or if an explicitly set state is pending
- if (m_LocalAuthoritativeNetworkState.ExplicitSet || CheckForStateChange(ref m_LocalAuthoritativeNetworkState, ref transformToCommit, synchronize, forceState: settingState))
+ if (m_LocalAuthoritativeNetworkState.ExplicitSet || CheckForStateChange(ref m_LocalAuthoritativeNetworkState, synchronize, forceState: settingState))
{
// If the state was explicitly set, then update the network tick to match the locally calculate tick
if (m_LocalAuthoritativeNetworkState.ExplicitSet)
@@ -1968,10 +2040,10 @@ private void TryCommitTransform(ref Transform transformToCommit, bool synchroniz
// that is outside of the normal internal tick flow.
m_LocalAuthoritativeNetworkState.NetworkTick = m_CachedNetworkManager.NetworkTickSystem.ServerTime.Tick;
- if (SwitchTransformSpaceWhenParented && m_LocalAuthoritativeNetworkState.ExplicitSet && m_LocalAuthoritativeNetworkState.IsDirty && transform.parent != null && !m_LocalAuthoritativeNetworkState.InLocalSpace)
+ if (SwitchTransformSpaceWhenParented && m_LocalAuthoritativeNetworkState.ExplicitSet && m_LocalAuthoritativeNetworkState.FlagStates.IsDirty && transform.parent != null && !m_LocalAuthoritativeNetworkState.InLocalSpace)
{
InLocalSpace = true;
- CheckForStateChange(ref m_LocalAuthoritativeNetworkState, ref transformToCommit, synchronize, forceState: true);
+ CheckForStateChange(ref m_LocalAuthoritativeNetworkState, synchronize, forceState: true);
}
}
@@ -1982,11 +2054,11 @@ private void TryCommitTransform(ref Transform transformToCommit, bool synchroniz
m_OldState = m_LocalAuthoritativeNetworkState;
// Preserve our teleporting flag in order to know if the state pushed was a teleport
- m_LocalAuthoritativeNetworkState.WasTeleported = m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame;
+ m_LocalAuthoritativeNetworkState.FlagStates.WasTeleported = m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame;
// Reset the teleport and explicit state flags after we have sent the state update.
// These could be set again in the below OnAuthorityPushTransformState virtual method
- m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = false;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsTeleportingNextFrame = false;
m_LocalAuthoritativeNetworkState.ExplicitSet = false;
try
@@ -2007,7 +2079,7 @@ private void TryCommitTransform(ref Transform transformToCommit, bool synchroniz
// frame synch "tick slot". Once we send a frame synch, if no other deltas occur after that
// (i.e. the object is at rest) then we will stop sending frame synch's until the object begins
// moving, rotating, or scaling again.
- if (UseUnreliableDeltas && !m_LocalAuthoritativeNetworkState.UnreliableFrameSync && !synchronize)
+ if (UseUnreliableDeltas && !m_LocalAuthoritativeNetworkState.FlagStates.UnreliableFrameSync && !synchronize)
{
m_DeltaSynch = true;
}
@@ -2066,10 +2138,10 @@ internal NetworkTransformState ApplyLocalNetworkState(Transform transform)
{
// Since we never commit these changes, we need to simulate that any changes were committed previously and the bitset
// value would already be reset prior to having the state applied
- m_LocalAuthoritativeNetworkState.ClearBitSetForNextTick();
+ m_LocalAuthoritativeNetworkState.FlagStates.ClearBitSetForNextTick();
// Now check the transform for any threshold value changes
- CheckForStateChange(ref m_LocalAuthoritativeNetworkState, ref transform);
+ CheckForStateChange(ref m_LocalAuthoritativeNetworkState);
// Return the entire state to be used by the integration test
return m_LocalAuthoritativeNetworkState;
@@ -2080,24 +2152,27 @@ internal NetworkTransformState ApplyLocalNetworkState(Transform transform)
///
internal bool ApplyTransformToNetworkState(ref NetworkTransformState networkState, double dirtyTime, Transform transformToUse)
{
+ CachedTransform = transformToUse;
m_CachedNetworkManager = NetworkManager;
// Apply the interpolate and PostionDeltaCompression flags, otherwise we get false positives whether something changed or not.
- networkState.UseInterpolation = Interpolate;
- networkState.QuaternionSync = UseQuaternionSynchronization;
- networkState.UseHalfFloatPrecision = UseHalfFloatPrecision;
- networkState.QuaternionCompression = UseQuaternionCompression;
- networkState.UseUnreliableDeltas = UseUnreliableDeltas;
+ networkState.FlagStates.UseInterpolation = Interpolate;
+ networkState.FlagStates.QuaternionSync = UseQuaternionSynchronization;
+ networkState.FlagStates.UseHalfFloatPrecision = UseHalfFloatPrecision;
+ networkState.FlagStates.QuaternionCompression = UseQuaternionCompression;
+ networkState.FlagStates.UseUnreliableDeltas = UseUnreliableDeltas;
m_HalfPositionState = new NetworkDeltaPosition(Vector3.zero, 0, math.bool3(SyncPositionX, SyncPositionY, SyncPositionZ));
- return CheckForStateChange(ref networkState, ref transformToUse);
+ return CheckForStateChange(ref networkState);
}
///
/// Applies the transform to the specified.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool CheckForStateChange(ref NetworkTransformState networkState, ref Transform transformToUse, bool isSynchronization = false, ulong targetClientId = 0, bool forceState = false)
+ private bool CheckForStateChange(ref NetworkTransformState networkState, bool isSynchronization = false, ulong targetClientId = 0, bool forceState = false)
{
+ var flagStates = networkState.FlagStates;
+
// As long as we are not doing our first synchronization and we are sending unreliable deltas, each
// NetworkTransform will stagger its full transfom synchronization over a 1 second period based on the
// assigned tick slot (m_TickSync).
@@ -2110,46 +2185,51 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
// We compare against the NetworkTickSystem version since ServerTime is set when updating ticks
if (UseUnreliableDeltas && !isSynchronization && m_DeltaSynch && m_NextTickSync <= CurrentTick)
{
+ // TODO-CACHE: m_CachedNetworkManager.NetworkConfig.TickRate value
// Increment to the next frame synch tick position for this instance
m_NextTickSync += (int)m_CachedNetworkManager.NetworkConfig.TickRate;
// If we are teleporting, we do not need to send a frame synch for this tick slot
// as a "frame synch" really is effectively just a teleport.
- isAxisSync = !networkState.IsTeleportingNextFrame;
+ isAxisSync = !flagStates.IsTeleportingNextFrame;
// Reset our delta synch trigger so we don't send another frame synch until we
// send at least 1 unreliable state update after this fame synch or teleport
m_DeltaSynch = false;
}
+
// This is used to determine if we need to send the state update reliably (if we are doing an axial sync)
- networkState.UnreliableFrameSync = isAxisSync;
+ flagStates.UnreliableFrameSync = isAxisSync;
- var isTeleportingAndNotSynchronizing = networkState.IsTeleportingNextFrame && !isSynchronization;
+ var isTeleportingAndNotSynchronizing = flagStates.IsTeleportingNextFrame && !isSynchronization;
var isDirty = false;
- var isPositionDirty = isTeleportingAndNotSynchronizing ? networkState.HasPositionChange : false;
- var isRotationDirty = isTeleportingAndNotSynchronizing ? networkState.HasRotAngleChange : false;
- var isScaleDirty = isTeleportingAndNotSynchronizing ? networkState.HasScaleChange : false;
- networkState.SwitchTransformSpaceWhenParented = SwitchTransformSpaceWhenParented;
+ var isPositionDirty = isTeleportingAndNotSynchronizing ? flagStates.HasPositionChange : false;
+ var isRotationDirty = isTeleportingAndNotSynchronizing ? flagStates.HasRotAngleChange : false;
+ var isScaleDirty = isTeleportingAndNotSynchronizing ? flagStates.HasScaleChange : false;
+
+ flagStates.SwitchTransformSpaceWhenParented = SwitchTransformSpaceWhenParented;
+
+
// All of the checks below, up to the delta position checking portion, are to determine if the
// authority changed a property during runtime that requires a full synchronizing.
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
- if ((InLocalSpace != networkState.InLocalSpace || isSynchronization) && !m_UseRigidbodyForMotion)
+ if ((InLocalSpace != flagStates.InLocalSpace || isSynchronization) && !m_UseRigidbodyForMotion)
#else
- if (InLocalSpace != networkState.InLocalSpace)
+ if (InLocalSpace != flagStates.InLocalSpace)
#endif
{
// When SwitchTransformSpaceWhenParented is set we automatically set our local space based on whether
// we are parented or not.
- networkState.InLocalSpace = SwitchTransformSpaceWhenParented ? transform.parent != null : InLocalSpace;
+ flagStates.InLocalSpace = SwitchTransformSpaceWhenParented ? transform.parent != null : InLocalSpace;
if (SwitchTransformSpaceWhenParented)
{
- InLocalSpace = networkState.InLocalSpace;
+ InLocalSpace = flagStates.InLocalSpace;
}
isDirty = true;
// If we are already teleporting preserve the teleport flag.
// If we don't have SwitchTransformSpaceWhenParented set or we are synchronizing,
// then set the teleport flag.
- networkState.IsTeleportingNextFrame |= !SwitchTransformSpaceWhenParented || isSynchronization;
+ flagStates.IsTeleportingNextFrame |= !SwitchTransformSpaceWhenParented || isSynchronization;
// Otherwise, if SwitchTransformSpaceWhenParented is set we force a full state update.
// If interpolation is enabled, then any non-authority instance will update any pending
@@ -2159,8 +2239,8 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
- var position = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetPosition() : InLocalSpace ? transformToUse.localPosition : transformToUse.position;
- var rotation = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetRotation() : InLocalSpace ? transformToUse.localRotation : transformToUse.rotation;
+ var position = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetPosition() : InLocalSpace ? CachedTransform.localPosition : CachedTransform.position;
+ var rotation = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetRotation() : InLocalSpace ? CachedTransform.localRotation : CachedTransform.rotation;
var positionThreshold = Vector3.one * PositionThreshold;
var rotationThreshold = Vector3.one * RotAngleThreshold;
@@ -2173,17 +2253,17 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
// rotationThreshold = m_NetworkRigidbodyInternal.GetAdjustedRotationThreshold();
//}
#else
- var position = InLocalSpace ? transformToUse.localPosition : transformToUse.position;
- var rotation = InLocalSpace ? transformToUse.localRotation : transformToUse.rotation;
+ var position = InLocalSpace ? CachedTransform.localPosition : CachedTransform.position;
+ var rotation = InLocalSpace ? CachedTransform.localRotation : CachedTransform.rotation;
var positionThreshold = Vector3.one * PositionThreshold;
var rotationThreshold = Vector3.one * RotAngleThreshold;
#endif
var rotAngles = rotation.eulerAngles;
- var scale = transformToUse.localScale;
- networkState.IsSynchronizing = isSynchronization;
+ var scale = CachedTransform.localScale;
+ flagStates.IsSynchronizing = isSynchronization;
// Check for parenting when synchronizing and/or teleporting
- if (isSynchronization || networkState.IsTeleportingNextFrame || forceState)
+ if (isSynchronization || flagStates.IsTeleportingNextFrame || forceState)
{
// This all has to do with complex nested hierarchies and how it impacts scale
// when set for the first time or teleporting and depends upon whether the
@@ -2212,80 +2292,80 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
}
}
- networkState.IsParented = hasParentNetworkObject;
+ flagStates.IsParented = hasParentNetworkObject;
}
- if (Interpolate != networkState.UseInterpolation)
+ if (Interpolate != flagStates.UseInterpolation)
{
- networkState.UseInterpolation = Interpolate;
+ flagStates.UseInterpolation = Interpolate;
isDirty = true;
// When we change from interpolating to not interpolating (or vice versa) we need to synchronize/reset everything
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
- if (UseQuaternionSynchronization != networkState.QuaternionSync)
+ if (UseQuaternionSynchronization != flagStates.QuaternionSync)
{
- networkState.QuaternionSync = UseQuaternionSynchronization;
+ flagStates.QuaternionSync = UseQuaternionSynchronization;
isDirty = true;
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
- if (UseQuaternionCompression != networkState.QuaternionCompression)
+ if (UseQuaternionCompression != flagStates.QuaternionCompression)
{
- networkState.QuaternionCompression = UseQuaternionCompression;
+ flagStates.QuaternionCompression = UseQuaternionCompression;
isDirty = true;
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
- if (UseHalfFloatPrecision != networkState.UseHalfFloatPrecision)
+ if (UseHalfFloatPrecision != flagStates.UseHalfFloatPrecision)
{
- networkState.UseHalfFloatPrecision = UseHalfFloatPrecision;
+ flagStates.UseHalfFloatPrecision = UseHalfFloatPrecision;
isDirty = true;
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
- if (SlerpPosition != networkState.UsePositionSlerp)
+ if (SlerpPosition != flagStates.UsePositionSlerp)
{
- networkState.UsePositionSlerp = SlerpPosition;
+ flagStates.UsePositionSlerp = SlerpPosition;
isDirty = true;
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
- if (UseUnreliableDeltas != networkState.UseUnreliableDeltas)
+ if (UseUnreliableDeltas != flagStates.UseUnreliableDeltas)
{
- networkState.UseUnreliableDeltas = UseUnreliableDeltas;
+ flagStates.UseUnreliableDeltas = UseUnreliableDeltas;
isDirty = true;
- networkState.IsTeleportingNextFrame = true;
+ flagStates.IsTeleportingNextFrame = true;
}
// Begin delta checks against last sent state update
if (!UseHalfFloatPrecision)
{
- if (SyncPositionX && (Mathf.Abs(networkState.PositionX - position.x) >= positionThreshold.x || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncPositionX && (Mathf.Abs(networkState.PositionX - position.x) >= positionThreshold.x || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.PositionX = position.x;
- networkState.HasPositionX = true;
+ flagStates.SetHasPosition(Axis.X, true);
isPositionDirty = true;
}
- if (SyncPositionY && (Mathf.Abs(networkState.PositionY - position.y) >= positionThreshold.y || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncPositionY && (Mathf.Abs(networkState.PositionY - position.y) >= positionThreshold.y || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.PositionY = position.y;
- networkState.HasPositionY = true;
+ flagStates.SetHasPosition(Axis.Y, true);
isPositionDirty = true;
}
- if (SyncPositionZ && (Mathf.Abs(networkState.PositionZ - position.z) >= positionThreshold.z || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncPositionZ && (Mathf.Abs(networkState.PositionZ - position.z) >= positionThreshold.z || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.PositionZ = position.z;
- networkState.HasPositionZ = true;
+ flagStates.SetHasPosition(Axis.Z, true);
isPositionDirty = true;
}
}
else if (SynchronizePosition)
{
// If we are teleporting then we can skip the delta threshold check
- isPositionDirty = networkState.IsTeleportingNextFrame || isAxisSync || forceState;
+ isPositionDirty = flagStates.IsTeleportingNextFrame || isAxisSync || forceState;
if (m_HalfFloatTargetTickOwnership > CurrentTick)
{
isPositionDirty = true;
@@ -2318,7 +2398,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
// With global teleporting (broadcast to all non-authority instances)
// we re-initialize authority's NetworkDeltaPosition and synchronize all
// non-authority instances with the new full precision position
- if (networkState.IsTeleportingNextFrame)
+ if (flagStates.IsTeleportingNextFrame)
{
m_HalfPositionState = new NetworkDeltaPosition(position, networkState.NetworkTick, math.bool3(SyncPositionX, SyncPositionY, SyncPositionZ));
networkState.CurrentPosition = position;
@@ -2332,13 +2412,13 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
networkState.NetworkDeltaPosition = m_HalfPositionState;
// If ownership offset is greater or we are doing an axial synchronization then synchronize the base position
- if ((m_HalfFloatTargetTickOwnership > CurrentTick || isAxisSync) && !networkState.IsTeleportingNextFrame)
+ if ((m_HalfFloatTargetTickOwnership > CurrentTick || isAxisSync) && !flagStates.IsTeleportingNextFrame)
{
- networkState.SynchronizeBaseHalfFloat = true;
+ flagStates.SynchronizeBaseHalfFloat = true;
}
else
{
- networkState.SynchronizeBaseHalfFloat = UseUnreliableDeltas ? m_HalfPositionState.CollapsedDeltaIntoBase : false;
+ flagStates.SynchronizeBaseHalfFloat = UseUnreliableDeltas ? m_HalfPositionState.CollapsedDeltaIntoBase : false;
}
}
else // If synchronizing is set, then use the current full position value on the server side
@@ -2383,39 +2463,40 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
// Add log entry for this update relative to the client being synchronized
AddLogEntry(ref networkState, targetClientId, true);
}
- networkState.HasPositionX = SyncPositionX;
- networkState.HasPositionY = SyncPositionY;
- networkState.HasPositionZ = SyncPositionZ;
+ flagStates.HasPositionX = SyncPositionX;
+ flagStates.HasPositionY = SyncPositionY;
+ flagStates.HasPositionZ = SyncPositionZ;
+ flagStates.HasPositionChange = SyncPositionX || SyncPositionY || SyncPositionZ;
}
}
if (!UseQuaternionSynchronization)
{
- if (SyncRotAngleX && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleX, rotAngles.x)) >= rotationThreshold.x || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncRotAngleX && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleX, rotAngles.x)) >= rotationThreshold.x || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.RotAngleX = rotAngles.x;
- networkState.HasRotAngleX = true;
+ flagStates.SetHasRotation(Axis.X, true);
isRotationDirty = true;
}
- if (SyncRotAngleY && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleY, rotAngles.y)) >= rotationThreshold.y || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncRotAngleY && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleY, rotAngles.y)) >= rotationThreshold.y || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.RotAngleY = rotAngles.y;
- networkState.HasRotAngleY = true;
+ flagStates.SetHasRotation(Axis.Y, true);
isRotationDirty = true;
}
- if (SyncRotAngleZ && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleZ, rotAngles.z)) >= rotationThreshold.z || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncRotAngleZ && (Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleZ, rotAngles.z)) >= rotationThreshold.z || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.RotAngleZ = rotAngles.z;
- networkState.HasRotAngleZ = true;
+ flagStates.SetHasRotation(Axis.Z, true);
isRotationDirty = true;
}
}
else if (SynchronizeRotation)
{
// If we are teleporting then we can skip the delta threshold check
- isRotationDirty = networkState.IsTeleportingNextFrame || isAxisSync || forceState;
+ isRotationDirty = flagStates.IsTeleportingNextFrame || isAxisSync || forceState;
// For quaternion synchronization, if one angle is dirty we send a full update
if (!isRotationDirty)
{
@@ -2432,20 +2513,18 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
if (isRotationDirty)
{
networkState.Rotation = rotation;
- networkState.HasRotAngleX = true;
- networkState.HasRotAngleY = true;
- networkState.HasRotAngleZ = true;
+ flagStates.MarkChanged(AxialType.Rotation, true);
}
}
// For scale, we need to check for parenting when synchronizing and/or teleporting (synchronization is always teleporting)
- if (networkState.IsTeleportingNextFrame)
+ if (flagStates.IsTeleportingNextFrame)
{
// If we are synchronizing and the associated NetworkObject has a parent then we want to send the
// LossyScale if the NetworkObject has a parent since NetworkObject spawn order is not guaranteed
- if (networkState.IsParented)
+ if (flagStates.IsParented)
{
- networkState.LossyScale = transform.lossyScale;
+ networkState.LossyScale = CachedTransform.lossyScale;
}
}
@@ -2454,24 +2533,24 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
{
if (!UseHalfFloatPrecision)
{
- if (SyncScaleX && (Mathf.Abs(networkState.ScaleX - scale.x) >= ScaleThreshold || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncScaleX && (Mathf.Abs(networkState.ScaleX - scale.x) >= ScaleThreshold || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.ScaleX = scale.x;
- networkState.HasScaleX = true;
+ flagStates.SetHasScale(Axis.X, true);
isScaleDirty = true;
}
- if (SyncScaleY && (Mathf.Abs(networkState.ScaleY - scale.y) >= ScaleThreshold || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncScaleY && (Mathf.Abs(networkState.ScaleY - scale.y) >= ScaleThreshold || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.ScaleY = scale.y;
- networkState.HasScaleY = true;
+ flagStates.SetHasScale(Axis.Y, true);
isScaleDirty = true;
}
- if (SyncScaleZ && (Mathf.Abs(networkState.ScaleZ - scale.z) >= ScaleThreshold || networkState.IsTeleportingNextFrame || isAxisSync || forceState))
+ if (SyncScaleZ && (Mathf.Abs(networkState.ScaleZ - scale.z) >= ScaleThreshold || flagStates.IsTeleportingNextFrame || isAxisSync || forceState))
{
networkState.ScaleZ = scale.z;
- networkState.HasScaleZ = true;
+ flagStates.SetHasScale(Axis.Z, true);
isScaleDirty = true;
}
}
@@ -2480,11 +2559,11 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
var previousScale = networkState.Scale;
for (int i = 0; i < 3; i++)
{
- if (Mathf.Abs(scale[i] - previousScale[i]) >= ScaleThreshold || networkState.IsTeleportingNextFrame || isAxisSync || forceState)
+ if (Mathf.Abs(scale[i] - previousScale[i]) >= ScaleThreshold || flagStates.IsTeleportingNextFrame || isAxisSync || forceState)
{
isScaleDirty = true;
networkState.Scale[i] = scale[i];
- networkState.SetHasScale(i, i == 0 ? SyncScaleX : i == 1 ? SyncScaleY : SyncScaleZ);
+ flagStates.SetHasScale((Axis)i, i == 0 ? SyncScaleX : i == 1 ? SyncScaleY : SyncScaleZ);
}
}
}
@@ -2492,19 +2571,19 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
else // Just apply the full local scale when synchronizing
if (SynchronizeScale)
{
+ var localScale = CachedTransform.localScale;
if (!UseHalfFloatPrecision)
{
- networkState.ScaleX = transform.localScale.x;
- networkState.ScaleY = transform.localScale.y;
- networkState.ScaleZ = transform.localScale.z;
+
+ networkState.ScaleX = localScale.x;
+ networkState.ScaleY = localScale.y;
+ networkState.ScaleZ = localScale.z;
}
else
{
- networkState.Scale = transform.localScale;
+ networkState.Scale = localScale;
}
- networkState.HasScaleX = true;
- networkState.HasScaleY = true;
- networkState.HasScaleZ = true;
+ flagStates.MarkChanged(AxialType.Scale, true);
isScaleDirty = true;
}
isDirty |= isPositionDirty || isRotationDirty || isScaleDirty;
@@ -2521,7 +2600,10 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
}
// Mark the state dirty for the next network tick update to clear out the bitset values
- networkState.IsDirty |= isDirty;
+ flagStates.IsDirty |= isDirty;
+
+ // Apply any flag state changes
+ networkState.FlagStates = flagStates;
return isDirty;
}
@@ -2560,9 +2642,8 @@ private void OnNetworkTick(bool isCalledFromParent = false)
}
#endif
- // Update any changes to the transform
- var transformSource = transform;
- OnUpdateAuthoritativeState(ref transformSource, isCalledFromParent);
+ // Update any changes to the transform based on the current state
+ OnUpdateAuthoritativeState(isCalledFromParent);
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
m_InternalCurrentPosition = m_LastStateTargetPosition = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetPosition() : GetSpaceRelativePosition();
m_InternalCurrentRotation = m_UseRigidbodyForMotion ? m_NetworkRigidbodyInternal.GetRotation() : GetSpaceRelativeRotation();
@@ -2623,6 +2704,7 @@ protected internal void ApplyAuthoritativeState()
}
#endif
var networkState = m_LocalAuthoritativeNetworkState;
+ var flagStates = m_LocalAuthoritativeNetworkState.FlagStates;
// The m_InternalCurrentPosition, m_InternalCurrentRotation, and m_InternalCurrentScale values are continually updated
// at the end of this method and assure that when not interpolating the non-authoritative side
// cannot make adjustments to any portions the transform not being synchronized.
@@ -2652,19 +2734,19 @@ protected internal void ApplyAuthoritativeState()
// setting.
if (!SwitchTransformSpaceWhenParented)
{
- InLocalSpace = networkState.InLocalSpace;
+ InLocalSpace = flagStates.InLocalSpace;
}
// Non-Authority Preservers the authority's transform state update modes
- Interpolate = networkState.UseInterpolation;
- UseHalfFloatPrecision = networkState.UseHalfFloatPrecision;
- UseQuaternionSynchronization = networkState.QuaternionSync;
- UseQuaternionCompression = networkState.QuaternionCompression;
- UseUnreliableDeltas = networkState.UseUnreliableDeltas;
+ Interpolate = flagStates.UseInterpolation;
+ UseHalfFloatPrecision = flagStates.UseHalfFloatPrecision;
+ UseQuaternionSynchronization = flagStates.QuaternionSync;
+ UseQuaternionCompression = flagStates.QuaternionCompression;
+ UseUnreliableDeltas = flagStates.UseUnreliableDeltas;
- if (SlerpPosition != networkState.UsePositionSlerp)
+ if (SlerpPosition != flagStates.UsePositionSlerp)
{
- SlerpPosition = networkState.UsePositionSlerp;
+ SlerpPosition = flagStates.UsePositionSlerp;
UpdatePositionSlerp();
}
@@ -2726,16 +2808,16 @@ protected internal void ApplyAuthoritativeState()
// Non-Interpolated Position and Scale
if (UseHalfFloatPrecision)
{
- if (networkState.HasPositionChange && SynchronizePosition)
+ if (flagStates.HasPositionChange && SynchronizePosition)
{
adjustedPosition = m_LastStateTargetPosition;
}
- if (networkState.HasScaleChange && SynchronizeScale)
+ if (flagStates.HasScaleChange && SynchronizeScale)
{
for (int i = 0; i < 3; i++)
{
- if (m_LocalAuthoritativeNetworkState.HasScale(i))
+ if (m_LocalAuthoritativeNetworkState.FlagStates.HasScale((Axis)i))
{
adjustedScale[i] = m_LocalAuthoritativeNetworkState.Scale[i];
}
@@ -2744,26 +2826,26 @@ protected internal void ApplyAuthoritativeState()
}
else
{
- if (networkState.HasPositionX) { adjustedPosition.x = networkState.PositionX; }
- if (networkState.HasPositionY) { adjustedPosition.y = networkState.PositionY; }
- if (networkState.HasPositionZ) { adjustedPosition.z = networkState.PositionZ; }
- if (networkState.HasScaleX) { adjustedScale.x = networkState.ScaleX; }
- if (networkState.HasScaleY) { adjustedScale.y = networkState.ScaleY; }
- if (networkState.HasScaleZ) { adjustedScale.z = networkState.ScaleZ; }
+ if (flagStates.HasPositionX) { adjustedPosition.x = networkState.PositionX; }
+ if (flagStates.HasPositionY) { adjustedPosition.y = networkState.PositionY; }
+ if (flagStates.HasPositionZ) { adjustedPosition.z = networkState.PositionZ; }
+ if (flagStates.HasScaleX) { adjustedScale.x = networkState.ScaleX; }
+ if (flagStates.HasScaleY) { adjustedScale.y = networkState.ScaleY; }
+ if (flagStates.HasScaleZ) { adjustedScale.z = networkState.ScaleZ; }
}
// Non-interpolated rotation
if (SynchronizeRotation)
{
- if (networkState.QuaternionSync && networkState.HasRotAngleChange)
+ if (flagStates.QuaternionSync && flagStates.HasRotAngleChange)
{
adjustedRotation = networkState.Rotation;
}
else
{
- if (networkState.HasRotAngleX) { adjustedRotAngles.x = networkState.RotAngleX; }
- if (networkState.HasRotAngleY) { adjustedRotAngles.y = networkState.RotAngleY; }
- if (networkState.HasRotAngleZ) { adjustedRotAngles.z = networkState.RotAngleZ; }
+ if (flagStates.HasRotAngleX) { adjustedRotAngles.x = networkState.RotAngleX; }
+ if (flagStates.HasRotAngleY) { adjustedRotAngles.y = networkState.RotAngleY; }
+ if (flagStates.HasRotAngleZ) { adjustedRotAngles.z = networkState.RotAngleZ; }
adjustedRotation.eulerAngles = adjustedRotAngles;
}
}
@@ -2773,7 +2855,7 @@ protected internal void ApplyAuthoritativeState()
if (SynchronizePosition)
{
// Update our current position if it changed or we are interpolating
- if (networkState.HasPositionChange || Interpolate)
+ if (flagStates.HasPositionChange || Interpolate)
{
if (SyncPositionX && SyncPositionY && SyncPositionZ)
{
@@ -2782,7 +2864,7 @@ protected internal void ApplyAuthoritativeState()
else
{
// Preserve any non-synchronized changes to the local instance's position
- var position = InLocalSpace ? transform.localPosition : transform.position;
+ var position = InLocalSpace ? CachedTransform.localPosition : CachedTransform.position;
m_InternalCurrentPosition.x = SyncPositionX ? adjustedPosition.x : position.x;
m_InternalCurrentPosition.y = SyncPositionY ? adjustedPosition.y : position.y;
m_InternalCurrentPosition.z = SyncPositionZ ? adjustedPosition.z : position.z;
@@ -2803,11 +2885,11 @@ protected internal void ApplyAuthoritativeState()
{
if (PositionInLocalSpace)
{
- transform.localPosition = m_InternalCurrentPosition;
+ CachedTransform.localPosition = m_InternalCurrentPosition;
}
else
{
- transform.position = m_InternalCurrentPosition;
+ CachedTransform.position = m_InternalCurrentPosition;
}
}
}
@@ -2825,7 +2907,7 @@ protected internal void ApplyAuthoritativeState()
else
{
// Preserve any non-synchronized changes to the local instance's rotation
- var rotation = InLocalSpace ? transform.localRotation.eulerAngles : transform.rotation.eulerAngles;
+ var rotation = InLocalSpace ? CachedTransform.localRotation.eulerAngles : CachedTransform.rotation.eulerAngles;
var currentEuler = m_InternalCurrentRotation.eulerAngles;
var updatedEuler = adjustedRotation.eulerAngles;
currentEuler.x = SyncRotAngleX ? updatedEuler.x : rotation.x;
@@ -2845,11 +2927,11 @@ protected internal void ApplyAuthoritativeState()
{
if (RotationInLocalSpace)
{
- transform.localRotation = m_InternalCurrentRotation;
+ CachedTransform.localRotation = m_InternalCurrentRotation;
}
else
{
- transform.rotation = m_InternalCurrentRotation;
+ CachedTransform.rotation = m_InternalCurrentRotation;
}
}
}
@@ -2858,7 +2940,7 @@ protected internal void ApplyAuthoritativeState()
if (SynchronizeScale)
{
// Update our current scale if it changed or we are interpolating
- if (networkState.HasScaleChange || Interpolate)
+ if (flagStates.HasScaleChange || Interpolate)
{
if (SyncScaleX && SyncScaleY && SyncScaleZ)
{
@@ -2867,13 +2949,13 @@ protected internal void ApplyAuthoritativeState()
else
{
// Preserve any non-synchronized changes to the local instance's scale
- var scale = transform.localScale;
+ var scale = CachedTransform.localScale;
m_InternalCurrentScale.x = SyncScaleX ? adjustedScale.x : scale.x;
m_InternalCurrentScale.y = SyncScaleY ? adjustedScale.y : scale.y;
m_InternalCurrentScale.z = SyncScaleZ ? adjustedScale.z : scale.z;
}
}
- transform.localScale = m_InternalCurrentScale;
+ CachedTransform.localScale = m_InternalCurrentScale;
}
OnTransformUpdated();
}
@@ -2895,31 +2977,32 @@ private void ApplyTeleportingState(NetworkTransformState newState)
var currentPosition = GetSpaceRelativePosition();
var currentRotation = GetSpaceRelativeRotation();
var currentEulerAngles = currentRotation.eulerAngles;
- var currentScale = transform.localScale;
+ var currentScale = CachedTransform.localScale;
var isSynchronization = newState.IsSynchronizing;
+ var flagStates = newState.FlagStates;
// Clear all interpolators
m_ScaleInterpolator.Clear();
m_PositionInterpolator.Clear();
m_RotationInterpolator.Clear();
- if (newState.HasPositionChange)
+ if (flagStates.HasPositionChange)
{
if (!UseHalfFloatPrecision)
{
// Adjust based on which axis changed
- if (newState.HasPositionX)
+ if (flagStates.HasPositionX)
{
currentPosition.x = newState.PositionX;
}
- if (newState.HasPositionY)
+ if (flagStates.HasPositionY)
{
currentPosition.y = newState.PositionY;
}
- if (newState.HasPositionZ)
+ if (flagStates.HasPositionZ)
{
currentPosition.z = newState.PositionZ;
}
@@ -2959,13 +3042,13 @@ private void ApplyTeleportingState(NetworkTransformState newState)
m_LastStateTargetPosition = currentPosition;
// Apply the position
- if (newState.InLocalSpace)
+ if (flagStates.InLocalSpace)
{
- transform.localPosition = currentPosition;
+ CachedTransform.localPosition = currentPosition;
}
else
{
- transform.position = currentPosition;
+ CachedTransform.position = currentPosition;
}
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
@@ -2981,7 +3064,7 @@ private void ApplyTeleportingState(NetworkTransformState newState)
}
}
- if (newState.HasScaleChange)
+ if (flagStates.HasScaleChange)
{
bool shouldUseLossy = false;
@@ -2992,17 +3075,17 @@ private void ApplyTeleportingState(NetworkTransformState newState)
else
{
// Adjust based on which axis changed
- if (newState.HasScaleX)
+ if (flagStates.HasScaleX)
{
currentScale.x = shouldUseLossy ? newState.LossyScale.x : newState.ScaleX;
}
- if (newState.HasScaleY)
+ if (flagStates.HasScaleY)
{
currentScale.y = shouldUseLossy ? newState.LossyScale.y : newState.ScaleY;
}
- if (newState.HasScaleZ)
+ if (flagStates.HasScaleZ)
{
currentScale.z = shouldUseLossy ? newState.LossyScale.z : newState.ScaleZ;
}
@@ -3012,7 +3095,7 @@ private void ApplyTeleportingState(NetworkTransformState newState)
m_TargetScale = currentScale;
// Apply the adjusted scale
- transform.localScale = currentScale;
+ CachedTransform.localScale = currentScale;
if (Interpolate)
{
@@ -3020,26 +3103,26 @@ private void ApplyTeleportingState(NetworkTransformState newState)
}
}
- if (newState.HasRotAngleChange)
+ if (flagStates.HasRotAngleChange)
{
- if (newState.QuaternionSync)
+ if (flagStates.QuaternionSync)
{
currentRotation = newState.Rotation;
}
else
{
// Adjust based on which axis changed
- if (newState.HasRotAngleX)
+ if (flagStates.HasRotAngleX)
{
currentEulerAngles.x = newState.RotAngleX;
}
- if (newState.HasRotAngleY)
+ if (flagStates.HasRotAngleY)
{
currentEulerAngles.y = newState.RotAngleY;
}
- if (newState.HasRotAngleZ)
+ if (flagStates.HasRotAngleZ)
{
currentEulerAngles.z = newState.RotAngleZ;
}
@@ -3051,17 +3134,17 @@ private void ApplyTeleportingState(NetworkTransformState newState)
if (InLocalSpace)
{
- transform.localRotation = currentRotation;
+ CachedTransform.localRotation = currentRotation;
}
else
{
- transform.rotation = currentRotation;
+ CachedTransform.rotation = currentRotation;
}
#if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D
if (m_UseRigidbodyForMotion)
{
- m_NetworkRigidbodyInternal.SetRotation(transform.rotation);
+ m_NetworkRigidbodyInternal.SetRotation(CachedTransform.rotation);
}
#endif
@@ -3069,7 +3152,7 @@ private void ApplyTeleportingState(NetworkTransformState newState)
{
m_RotationInterpolator.AutoConvertTransformSpace = SwitchTransformSpaceWhenParented;
m_RotationInterpolator.InLocalSpace = newState.InLocalSpace;
- m_RotationInterpolator.ResetTo(transform.parent, currentRotation, sentTime);
+ m_RotationInterpolator.ResetTo(CachedTransform.parent, currentRotation, sentTime);
}
}
@@ -3092,30 +3175,31 @@ private void ApplyTeleportingState(NetworkTransformState newState)
///
internal void ApplyUpdatedState(NetworkTransformState newState)
{
+ var flagStates = newState.FlagStates;
// Set the transforms's synchronization modes
- InLocalSpace = newState.InLocalSpace;
- Interpolate = newState.UseInterpolation;
- UseQuaternionSynchronization = newState.QuaternionSync;
- UseQuaternionCompression = newState.QuaternionCompression;
- UseHalfFloatPrecision = newState.UseHalfFloatPrecision;
- UseUnreliableDeltas = newState.UseUnreliableDeltas;
+ InLocalSpace = flagStates.InLocalSpace;
+ Interpolate = flagStates.UseInterpolation;
+ UseQuaternionSynchronization = flagStates.QuaternionSync;
+ UseQuaternionCompression = flagStates.QuaternionCompression;
+ UseHalfFloatPrecision = flagStates.UseHalfFloatPrecision;
+ UseUnreliableDeltas = flagStates.UseUnreliableDeltas;
- SwitchTransformSpaceWhenParented = newState.SwitchTransformSpaceWhenParented;
+ SwitchTransformSpaceWhenParented = flagStates.SwitchTransformSpaceWhenParented;
- if (SlerpPosition != newState.UsePositionSlerp)
+ if (SlerpPosition != flagStates.UsePositionSlerp)
{
- SlerpPosition = newState.UsePositionSlerp;
+ SlerpPosition = flagStates.UsePositionSlerp;
UpdatePositionSlerp();
}
m_LocalAuthoritativeNetworkState = newState;
- if (m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame)
+ if (flagStates.IsTeleportingNextFrame)
{
LastTickSync = m_LocalAuthoritativeNetworkState.GetNetworkTick();
ApplyTeleportingState(m_LocalAuthoritativeNetworkState);
return;
}
- else if (m_LocalAuthoritativeNetworkState.IsSynchronizing)
+ else if (flagStates.IsSynchronizing)
{
LastTickSync = m_LocalAuthoritativeNetworkState.GetNetworkTick();
}
@@ -3124,10 +3208,10 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
var currentRotation = GetSpaceRelativeRotation();
// Only if using half float precision and our position had changed last update then
- if (UseHalfFloatPrecision && m_LocalAuthoritativeNetworkState.HasPositionChange)
+ if (UseHalfFloatPrecision && flagStates.HasPositionChange)
{
// Do a full precision synchronization to apply the base position and offset.
- if (m_LocalAuthoritativeNetworkState.SynchronizeBaseHalfFloat)
+ if (flagStates.SynchronizeBaseHalfFloat)
{
m_HalfPositionState = m_LocalAuthoritativeNetworkState.NetworkDeltaPosition;
}
@@ -3155,25 +3239,25 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
// Apply axial changes from the new state
// Either apply the delta position target position or the current state's delta position
// depending upon whether UsePositionDeltaCompression is enabled
- if (m_LocalAuthoritativeNetworkState.HasPositionChange)
+ if (flagStates.HasPositionChange)
{
// If interpolating, get the current value as the final next position or current position
// depending upon if the interpolator is still processing a state or not.
- if (!m_LocalAuthoritativeNetworkState.UseHalfFloatPrecision)
+ if (!flagStates.UseHalfFloatPrecision)
{
var newTargetPosition = (Interpolate && SwitchTransformSpaceWhenParented) ? m_PositionInterpolator.GetInterpolatedValue() : m_LastStateTargetPosition;
var position = m_LocalAuthoritativeNetworkState.GetPosition();
- if (m_LocalAuthoritativeNetworkState.HasPositionX)
+ if (flagStates.HasPositionX)
{
newTargetPosition.x = position.x;
}
- if (m_LocalAuthoritativeNetworkState.HasPositionY)
+ if (flagStates.HasPositionY)
{
newTargetPosition.y = position.y;
}
- if (m_LocalAuthoritativeNetworkState.HasPositionZ)
+ if (flagStates.HasPositionZ)
{
newTargetPosition.z = position.z;
}
@@ -3183,14 +3267,14 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
UpdatePositionInterpolator(m_LastStateTargetPosition, sentTime);
}
- if (m_LocalAuthoritativeNetworkState.HasScaleChange)
+ if (flagStates.HasScaleChange)
{
var currentScale = m_TargetScale;
if (UseHalfFloatPrecision)
{
for (int i = 0; i < 3; i++)
{
- if (m_LocalAuthoritativeNetworkState.HasScale(i))
+ if (m_LocalAuthoritativeNetworkState.FlagStates.HasScale((Axis)i))
{
currentScale[i] = m_LocalAuthoritativeNetworkState.Scale[i];
}
@@ -3198,17 +3282,17 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
}
else
{
- if (m_LocalAuthoritativeNetworkState.HasScaleX)
+ if (flagStates.HasScaleX)
{
currentScale.x = m_LocalAuthoritativeNetworkState.ScaleX;
}
- if (m_LocalAuthoritativeNetworkState.HasScaleY)
+ if (flagStates.HasScaleY)
{
currentScale.y = m_LocalAuthoritativeNetworkState.ScaleY;
}
- if (m_LocalAuthoritativeNetworkState.HasScaleZ)
+ if (flagStates.HasScaleZ)
{
currentScale.z = m_LocalAuthoritativeNetworkState.ScaleZ;
}
@@ -3220,9 +3304,9 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
// With rotation, we check if there are any changes first and
// if so then apply the changes to the current Euler rotation
// values.
- if (m_LocalAuthoritativeNetworkState.HasRotAngleChange)
+ if (flagStates.HasRotAngleChange)
{
- if (m_LocalAuthoritativeNetworkState.QuaternionSync)
+ if (flagStates.QuaternionSync)
{
currentRotation = m_LocalAuthoritativeNetworkState.Rotation;
}
@@ -3231,17 +3315,17 @@ internal void ApplyUpdatedState(NetworkTransformState newState)
var currentEulerAngles = m_TargetRotation;
// Adjust based on which axis changed
// (both half precision and full precision apply Eulers to the RotAngle properties when reading the update)
- if (m_LocalAuthoritativeNetworkState.HasRotAngleX)
+ if (flagStates.HasRotAngleX)
{
currentEulerAngles.x = m_LocalAuthoritativeNetworkState.RotAngleX;
}
- if (m_LocalAuthoritativeNetworkState.HasRotAngleY)
+ if (flagStates.HasRotAngleY)
{
currentEulerAngles.y = m_LocalAuthoritativeNetworkState.RotAngleY;
}
- if (m_LocalAuthoritativeNetworkState.HasRotAngleZ)
+ if (flagStates.HasRotAngleZ)
{
currentEulerAngles.z = m_LocalAuthoritativeNetworkState.RotAngleZ;
}
@@ -3280,7 +3364,7 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf
// If we are using UseUnreliableDeltas and our old state tick is greater than the new state tick,
// then just ignore the newstate. This avoids any scenario where the new state is out of order
// from the old state (with unreliable traffic and/or mixed unreliable and reliable)
- if (UseUnreliableDeltas && oldState.NetworkTick > newState.NetworkTick && !newState.IsTeleportingNextFrame && !newState.UnreliableFrameSync)
+ if (UseUnreliableDeltas && oldState.NetworkTick > newState.NetworkTick && !newState.FlagStates.IsTeleportingNextFrame && !newState.FlagStates.UnreliableFrameSync)
{
return;
}
@@ -3291,16 +3375,16 @@ private void OnNetworkStateChanged(NetworkTransformState oldState, NetworkTransf
if (LogStateUpdate)
{
var builder = new StringBuilder();
- builder.AppendLine($"[Client-{m_CachedNetworkManager.LocalClientId}][State Update: {newState.GetNetworkTick()}][HasPos: {newState.HasPositionChange}][Has Rot: {newState.HasRotAngleChange}][Has Scale: {newState.HasScaleChange}]");
- if (newState.HasPositionChange)
+ builder.AppendLine($"[Client-{m_CachedNetworkManager.LocalClientId}][State Update: {newState.GetNetworkTick()}][HasPos: {newState.FlagStates.HasPositionChange}][Has Rot: {newState.FlagStates.HasRotAngleChange}][Has Scale: {newState.FlagStates.HasScaleChange}]");
+ if (newState.FlagStates.HasPositionChange)
{
builder.AppendLine($"Position = {newState.GetPosition()}");
}
- if (newState.HasRotAngleChange)
+ if (newState.FlagStates.HasRotAngleChange)
{
builder.AppendLine($"Rotation = {newState.GetRotation()}");
}
- if (newState.HasScaleChange)
+ if (newState.FlagStates.HasScaleChange)
{
builder.AppendLine($"Scale = {newState.GetScale()}");
}
@@ -3412,7 +3496,7 @@ private void AxisChangedDeltaPositionCheck()
needsToTeleport = Mathf.Abs(relativePosition.z - positionState.z) >= NetworkDeltaPosition.MaxDeltaBeforeAdjustment;
}
// If needed, force a teleport as the delta is outside of the valid delta boundary
- m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = needsToTeleport;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsTeleportingNextFrame = needsToTeleport;
}
}
}
@@ -3421,27 +3505,27 @@ private void AxisChangedDeltaPositionCheck()
/// Called by authority to check for deltas and update non-authoritative instances
/// if any are found.
///
- internal void OnUpdateAuthoritativeState(ref Transform transformSource, bool settingState = false)
+ internal void OnUpdateAuthoritativeState(bool settingState = false)
{
// If our replicated state is not dirty and our local authority state is dirty, clear it.
- if (!m_LocalAuthoritativeNetworkState.ExplicitSet && m_LocalAuthoritativeNetworkState.IsDirty && !m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame)
+ if (!m_LocalAuthoritativeNetworkState.ExplicitSet && m_LocalAuthoritativeNetworkState.FlagStates.IsDirty && !m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame)
{
// Now clear our bitset and prepare for next network tick state update
- m_LocalAuthoritativeNetworkState.ClearBitSetForNextTick();
+ m_LocalAuthoritativeNetworkState.FlagStates.ClearBitSetForNextTick();
if (TrackByStateId)
{
- m_LocalAuthoritativeNetworkState.TrackByStateId = true;
+ m_LocalAuthoritativeNetworkState.FlagStates.TrackByStateId = true;
m_LocalAuthoritativeNetworkState.StateId++;
}
else
{
- m_LocalAuthoritativeNetworkState.TrackByStateId = false;
+ m_LocalAuthoritativeNetworkState.FlagStates.TrackByStateId = false;
}
}
AxisChangedDeltaPositionCheck();
- TryCommitTransform(ref transformSource, settingState: settingState);
+ TryCommitTransform(settingState: settingState);
}
#endregion
@@ -3492,12 +3576,12 @@ protected internal override void InternalOnNetworkSessionSynchronized()
private void ApplyPlayerTransformState()
{
- SynchronizeState.InLocalSpace = InLocalSpace;
- SynchronizeState.UseInterpolation = Interpolate;
- SynchronizeState.QuaternionSync = UseQuaternionSynchronization;
- SynchronizeState.UseHalfFloatPrecision = UseHalfFloatPrecision;
- SynchronizeState.QuaternionCompression = UseQuaternionCompression;
- SynchronizeState.UsePositionSlerp = SlerpPosition;
+ SynchronizeState.FlagStates.InLocalSpace = InLocalSpace;
+ SynchronizeState.FlagStates.UseInterpolation = Interpolate;
+ SynchronizeState.FlagStates.QuaternionSync = UseQuaternionSynchronization;
+ SynchronizeState.FlagStates.UseHalfFloatPrecision = UseHalfFloatPrecision;
+ SynchronizeState.FlagStates.QuaternionCompression = UseQuaternionCompression;
+ SynchronizeState.FlagStates.UsePositionSlerp = SlerpPosition;
}
///
@@ -3521,7 +3605,7 @@ protected internal override void InternalOnNetworkPostSpawn()
if (m_IsFirstNetworkTransform)
{
// Assure the NetworkTransform has the synchronizing flag set so the server runs through the final post initialization steps
- SynchronizeState.IsSynchronizing = true;
+ SynchronizeState.FlagStates.IsSynchronizing = true;
// Assure the SynchronizeState matches the initial prefab's values for each associated NetworkTransfrom (this includes root + all children)
foreach (var child in NetworkObject.NetworkTransforms)
@@ -3557,6 +3641,8 @@ protected internal override void InternalOnNetworkPostSpawn()
internal static bool AssignDefaultInterpolationType;
internal static InterpolationTypes DefaultInterpolationType;
+ internal Transform CachedTransform;
+
///
/// Create interpolators when first instantiated to avoid memory allocations if the
/// associated NetworkObject persists (i.e. despawned but not destroyed or pools)
@@ -3579,6 +3665,15 @@ protected virtual void Awake()
{
InLocalSpace = false;
}
+
+ CachedTransform = transform;
+ }
+
+ internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManager)
+ {
+ m_CachedNetworkManager = networkManager;
+ CachedTransform = transform;
+ base.InternalOnNetworkPreSpawn(ref networkManager);
}
///
@@ -3737,7 +3832,7 @@ private void InternalInitialization(bool isOwnershipChange = false)
#else
var forUpdate = true;
#endif
- m_LocalAuthoritativeNetworkState.SynchronizeBaseHalfFloat = false;
+ m_LocalAuthoritativeNetworkState.FlagStates.SynchronizeBaseHalfFloat = false;
if (CanCommitToTransform)
{
@@ -3746,7 +3841,7 @@ private void InternalInitialization(bool isOwnershipChange = false)
if (UseHalfFloatPrecision)
{
m_HalfPositionState = new NetworkDeltaPosition(currentPosition, m_CachedNetworkManager.ServerTime.Tick, math.bool3(SyncPositionX, SyncPositionY, SyncPositionZ));
- m_LocalAuthoritativeNetworkState.SynchronizeBaseHalfFloat = isOwnershipChange;
+ m_LocalAuthoritativeNetworkState.FlagStates.SynchronizeBaseHalfFloat = isOwnershipChange;
SetState(teleportDisabled: false);
}
@@ -4016,7 +4111,7 @@ public void SetState(Vector3? posIn = null, Quaternion? rotIn = null, Vector3? s
#endif
Vector3 pos = posIn == null ? position : posIn.Value;
Quaternion rot = rotIn == null ? rotation : rotIn.Value;
- Vector3 scale = scaleIn == null ? transform.localScale : scaleIn.Value;
+ Vector3 scale = scaleIn == null ? CachedTransform.localScale : scaleIn.Value;
if (!CanCommitToTransform)
{
@@ -4064,18 +4159,16 @@ private void SetStateInternal(Vector3 pos, Quaternion rot, Vector3 scale, bool s
}
transform.localScale = scale;
- m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = shouldTeleport;
-
- var transformToCommit = transform;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsTeleportingNextFrame = shouldTeleport;
// Explicit set states are cumulative during a fractional tick period of time (i.e. each SetState invocation will
// update the axial deltas to whatever changes are applied). As such, we need to preserve the dirty and explicit
// state flags.
- var stateWasDirty = m_LocalAuthoritativeNetworkState.IsDirty;
+ var stateWasDirty = m_LocalAuthoritativeNetworkState.FlagStates.IsDirty;
var explicitState = m_LocalAuthoritativeNetworkState.ExplicitSet;
// Apply any delta states to the m_LocalAuthoritativeNetworkState
- var isDirty = CheckForStateChange(ref m_LocalAuthoritativeNetworkState, ref transformToCommit);
+ var isDirty = CheckForStateChange(ref m_LocalAuthoritativeNetworkState);
// If we were dirty and the explicit state was set (prior to checking for deltas) or the current explicit state is dirty,
// then we set the explicit state flag.
@@ -4084,7 +4177,7 @@ private void SetStateInternal(Vector3 pos, Quaternion rot, Vector3 scale, bool s
// If the current explicit set flag is set, then we are dirty. This assures if more than one explicit set state is invoked
// in between a fractional tick period and the current explicit set state did not find any deltas that we preserve any
// previous dirty state.
- m_LocalAuthoritativeNetworkState.IsDirty = m_LocalAuthoritativeNetworkState.ExplicitSet;
+ m_LocalAuthoritativeNetworkState.FlagStates.IsDirty = m_LocalAuthoritativeNetworkState.ExplicitSet;
}
///
@@ -4626,8 +4719,8 @@ private void UpdateTransformState()
// - If UsUnrealiable is not enabled
// - If teleporting or synchronizing
// - If sending an UnrealiableFrameSync or synchronizing the base position of the NetworkDeltaPosition
- var networkDelivery = !UseUnreliableDeltas | m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame | m_LocalAuthoritativeNetworkState.IsSynchronizing
- | m_LocalAuthoritativeNetworkState.UnreliableFrameSync | m_LocalAuthoritativeNetworkState.SynchronizeBaseHalfFloat
+ var networkDelivery = !UseUnreliableDeltas | m_LocalAuthoritativeNetworkState.FlagStates.IsTeleportingNextFrame | m_LocalAuthoritativeNetworkState.FlagStates.IsSynchronizing
+ | m_LocalAuthoritativeNetworkState.FlagStates.UnreliableFrameSync | m_LocalAuthoritativeNetworkState.FlagStates.SynchronizeBaseHalfFloat
? MessageDeliveryType.DefaultDelivery : NetworkDelivery.UnreliableSequenced;
// Server-host-dahost always sends updates to all clients (but itself)
diff --git a/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs b/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
index 1421372839..0d6e3d494d 100644
--- a/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Components/RigidbodyContactEventManager.cs
@@ -80,8 +80,13 @@ public class RigidbodyContactEventManager : MonoBehaviour
private struct JobResultStruct
{
public bool HasCollisionStay;
+#if UNITY_6000_2_OR_NEWER
+ public EntityId ThisInstanceID;
+ public EntityId OtherInstanceID;
+#else
public int ThisInstanceID;
public int OtherInstanceID;
+#endif
public Vector3 AverageNormal;
public Vector3 AverageCollisionStayNormal;
public Vector3 ContactPoint;
@@ -90,10 +95,15 @@ private struct JobResultStruct
private NativeArray m_ResultsArray;
private int m_Count = 0;
private JobHandle m_JobHandle;
-
+#if UNITY_6000_2_OR_NEWER
+ private readonly Dictionary m_RigidbodyMapping = new Dictionary();
+ private readonly Dictionary m_HandlerMapping = new Dictionary();
+ private readonly Dictionary m_HandlerInfo = new Dictionary();
+#else
private readonly Dictionary m_RigidbodyMapping = new Dictionary();
private readonly Dictionary m_HandlerMapping = new Dictionary();
private readonly Dictionary m_HandlerInfo = new Dictionary();
+#endif
private void OnEnable()
{
diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs
index 1b14927f84..cf207cc725 100644
--- a/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Transports/UTP/UnityTransport.cs
@@ -356,6 +356,19 @@ private struct PacketLossCache
public float PacketLoss;
};
+ ///
+ /// TODO-FIXME:
+ /// Multiplayer Tools subscribes to this event and does not have the EntityId udpate.
+ ///
+#if FIXED
+#if UNITY_6000_2_OR_NEWER
+ internal static event Action TransportInitialized;
+ internal static event Action TransportDisposed;
+#else
+ internal static event Action TransportInitialized;
+ internal static event Action TransportDisposed;
+#endif
+#endif
internal static event Action TransportInitialized;
internal static event Action TransportDisposed;
@@ -435,7 +448,14 @@ private void InitDriver()
out m_UnreliableSequencedFragmentedPipeline,
out m_ReliableSequencedPipeline);
#if UNITY_6000_2_OR_NEWER
- TransportInitialized?.Invoke(GetEntityId(), m_Driver);
+ var entityId = GetEntityId();
+#if UNITY_6000_3_0A6_OR_HIGHER
+ // TODO-FIXME: Since multiplayer tools subscribes to this and we have to validate against any package that
+ // might use this action, we have to cast it down temporarily to avoid being blocked from getting these fixes in place.
+ TransportInitialized?.Invoke((int)entityId.GetRawData(), m_Driver);
+#else
+ TransportInitialized?.Invoke(entityId, m_Driver);
+#endif
#else
TransportInitialized?.Invoke(GetInstanceID(), m_Driver);
#endif
@@ -456,7 +476,15 @@ private void DisposeInternals()
m_SendQueue.Clear();
#if UNITY_6000_2_OR_NEWER
- TransportDisposed?.Invoke(GetEntityId());
+ var entityId = GetEntityId();
+#if UNITY_6000_3_0A6_OR_HIGHER
+ // TODO-FIXME: Since multiplayer tools subscribes to this and we have to validate against any package that
+ // might use this action, we have to cast it down temporarily to avoid being blocked from getting these fixes in place.
+ TransportDisposed?.Invoke((int)entityId.GetRawData());
+#else
+ TransportDisposed?.Invoke(entityId, m_Driver);
+#endif
+
#else
TransportDisposed?.Invoke(GetInstanceID());
#endif
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformBase.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformBase.cs
index ba03c78fb4..5ed20dd6cd 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformBase.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformBase.cs
@@ -824,7 +824,7 @@ public void CommitToTransform()
public (bool isDirty, bool isPositionDirty, bool isRotationDirty, bool isScaleDirty) ApplyState()
{
var transformState = ApplyLocalNetworkState(transform);
- return (transformState.IsDirty, transformState.HasPositionChange, transformState.HasRotAngleChange, transformState.HasScaleChange);
+ return (transformState.FlagStates.IsDirty, transformState.FlagStates.HasPositionChange, transformState.FlagStates.HasRotAngleChange, transformState.FlagStates.HasScaleChange);
}
}
@@ -986,7 +986,7 @@ private void LogState(ref NetworkTransformState state, bool isPush)
tick = NetworkManager.ServerTime.Tick;
}
- m_ChildStateLog.AppendLine($"[{state.NetworkTick}][{tick}] Tele:{state.IsTeleportingNextFrame} Sync: {state.IsSynchronizing} Reliable: {state.IsReliableStateUpdate()} IsParented: {state.IsParented} HasPos: {state.HasPositionChange} Pos: {state.GetPosition()}");
+ m_ChildStateLog.AppendLine($"[{state.NetworkTick}][{tick}] Tele:{state.FlagStates.IsTeleportingNextFrame} Sync: {state.FlagStates.IsSynchronizing} Reliable: {state.IsReliableStateUpdate()} IsParented: {state.FlagStates.IsParented} HasPos: {state.FlagStates.HasPositionChange} Pos: {state.GetPosition()}");
m_ChildStateLog.AppendLine($"Lossy:{state.LossyScale} Scale: {state.GetScale()} Rotation: {state.GetRotation()}");
}
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformGeneral.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformGeneral.cs
index 04afd12cb5..941e781d50 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformGeneral.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformGeneral.cs
@@ -55,12 +55,12 @@ public void TestMultipleStateSynchronization([Values] bool isLocal, [Values] boo
var localState = m_NonAuthoritativeTransform.LocalAuthoritativeNetworkState;
// Assure this is not set to avoid a false positive result with teleporting
- localState.IsTeleportingNextFrame = false;
+ localState.FlagStates.IsTeleportingNextFrame = false;
// Simulate a state update
- localState.UseInterpolation = false;
+ localState.FlagStates.UseInterpolation = false;
localState.CurrentPosition = new Vector3(5.0f, 0.0f, 0.0f);
- localState.HasPositionX = true;
+ localState.FlagStates.SetHasPosition(NetworkTransform.Axis.X, true);
localState.PositionX = 5.0f;
localState.NetworkTick++;
@@ -85,8 +85,8 @@ public void TestMultipleStateSynchronization([Values] bool isLocal, [Values] boo
Assert.IsTrue(localState.NetworkTick == lastStateTick, $"Previous Non-authority state tick was {lastStateTick} but is now {localState.NetworkTick}. Authority pushed a state update.");
// Simualate a 2nd state update on a different position axis
- localState.HasPositionX = false;
- localState.HasPositionZ = true;
+ localState.FlagStates.SetHasPosition(NetworkTransform.Axis.X, false);
+ localState.FlagStates.SetHasPosition(NetworkTransform.Axis.Z, true);
localState.PositionZ = -5.0f;
localState.NetworkTick++;
m_NonAuthoritativeTransform.ApplyUpdatedState(localState);
@@ -355,6 +355,7 @@ public void TestMultipleExplicitSetStates([Values] Interpolation interpolation)
[Test]
public void NonAuthorityOwnerSettingStateTest([Values] Interpolation interpolation, [Values] SmoothLerpSettings smoothLerp)
{
+ m_EnableVerboseDebug = true;
var interpolate = interpolation == Interpolation.EnableInterpolate;
var usingSmoothLerp = (smoothLerp == SmoothLerpSettings.SmoothLerp) && interpolate;
var waitForDelay = usingSmoothLerp ? 1000 : 500;
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformStateTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformStateTests.cs
index 67e66b61b3..7f63353e8f 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformStateTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/NetworkTransformStateTests.cs
@@ -1,12 +1,204 @@
+using System;
using NUnit.Framework;
+using Unity.Collections;
using Unity.Netcode.Components;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
+using static Unity.Netcode.Components.NetworkTransform;
+using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
+ // These tests do not need to run against the Rust server.
+ [IgnoreIfServiceEnvironmentVariableSet]
+ internal class NetworkTransformStateTests
+ {
+ [Test]
+ public void NetworkTransformStateFlags()
+ {
+ // The current number of flags on the NetworkTransformState
+ var numFlags = 24;
+
+ var indexValues = new uint[numFlags];
+
+ var currentFlag = (uint)0x00000001;
+ for (int j = 0; j < numFlags - 1; j++)
+ {
+ indexValues[j] = currentFlag;
+ currentFlag = currentFlag << 1;
+ }
+
+ // TrackByStateId is unique
+ indexValues[numFlags - 1] = 0x10000000;
+
+ var boolSet = new bool[numFlags];
+
+ InlinedBitmathSerialization(ref numFlags, ref indexValues, ref boolSet);
+ }
+
+
+ private void InlinedBitmathSerialization(ref int numFlags, ref uint[] indexValues, ref bool[] boolSet)
+ {
+ NetworkTransformState transformState;
+ FastBufferWriter writer;
+ FastBufferReader reader;
+ // Test setting one at a time.
+ for (int j = 0; j < numFlags; j++)
+ {
+ // reset previous test if needed
+ if (j > 0)
+ {
+ boolSet[j - 1] = false;
+ }
+
+ boolSet[j] = true;
+
+ transformState = new NetworkTransformState()
+ {
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = boolSet[0],
+ HasPositionX = boolSet[1],
+ HasPositionY = boolSet[2],
+ HasPositionZ = boolSet[3],
+ HasRotAngleX = boolSet[4],
+ HasRotAngleY = boolSet[5],
+ HasRotAngleZ = boolSet[6],
+ HasScaleX = boolSet[7],
+ HasScaleY = boolSet[8],
+ HasScaleZ = boolSet[9],
+ IsTeleportingNextFrame = boolSet[10],
+ UseInterpolation = boolSet[11],
+ QuaternionSync = boolSet[12],
+ QuaternionCompression = boolSet[13],
+ UseHalfFloatPrecision = boolSet[14],
+ IsSynchronizing = boolSet[15],
+ UsePositionSlerp = boolSet[16],
+ IsParented = boolSet[17],
+ SynchronizeBaseHalfFloat = boolSet[18],
+ ReliableSequenced = boolSet[19],
+ UseUnreliableDeltas = boolSet[20],
+ UnreliableFrameSync = boolSet[21],
+ SwitchTransformSpaceWhenParented = boolSet[22],
+ TrackByStateId = boolSet[23],
+ },
+ };
+
+ writer = new FastBufferWriter(64, Allocator.Temp);
+ BytePacker.WriteValueBitPacked(writer, transformState.FlagStates.GetFlags());
+
+ // Test the bitset representation of the serialization matches the pre-refactor serialization
+ reader = new FastBufferReader(writer, Allocator.None);
+ ByteUnpacker.ReadValueBitPacked(reader, out uint serializedBitset);
+
+ Assert.True((serializedBitset & indexValues[j]) == indexValues[j], $"[FlagTest][Individual] Set flag value {indexValues[j]} at index {j}, but BitSet value did not match!");
+
+ // reset the reader to the beginning of the buffer
+ reader.Seek(0);
+
+ ByteUnpacker.ReadValueBitPacked(reader, out uint bitFlags);
+ // Test the deserialized values match the original values
+ var deserialized = new NetworkTransformState();
+ // Set the flags
+ deserialized.FlagStates.SetFlags(bitFlags);
+
+ AssertTransformStateEquals(boolSet, deserialized, "Flag serialization");
+ }
+ // Test setting all flag values
+ transformState = new NetworkTransformState()
+ {
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = true,
+ HasPositionX = true,
+ HasPositionY = true,
+ HasPositionZ = true,
+ HasRotAngleX = true,
+ HasRotAngleY = true,
+ HasRotAngleZ = true,
+ HasScaleX = true,
+ HasScaleY = true,
+ HasScaleZ = true,
+ IsTeleportingNextFrame = true,
+ UseInterpolation = true,
+ QuaternionSync = true,
+ QuaternionCompression = true,
+ UseHalfFloatPrecision = true,
+ IsSynchronizing = true,
+ UsePositionSlerp = true,
+ IsParented = true,
+ SynchronizeBaseHalfFloat = true,
+ ReliableSequenced = true,
+ UseUnreliableDeltas = true,
+ UnreliableFrameSync = true,
+ SwitchTransformSpaceWhenParented = true,
+ TrackByStateId = true,
+ },
+ };
+
+ writer = new FastBufferWriter(64, Allocator.Temp);
+ BytePacker.WriteValueBitPacked(writer, transformState.FlagStates.GetFlags());
+
+ var serializedBuffer = writer.ToArray();
+
+ // Use a uint to set all bits to true in a legacy style bitset
+ uint bitset = 0;
+ for (int i = 0; i < numFlags; i++)
+ {
+ bitset |= indexValues[i];
+ }
+
+ var legacyBitsetWriter = new FastBufferWriter(64, Allocator.Temp);
+ BytePacker.WriteValueBitPacked(legacyBitsetWriter, bitset);
+
+ // Test refactored serialization matches pre-refactor flag serialization
+ Assert.AreEqual(legacyBitsetWriter.ToArray(), serializedBuffer, "[Flag serialization] Serialized NetworkTransformState doesn't match original serialization!");
+
+ reader = new FastBufferReader(legacyBitsetWriter, Allocator.None);
+ ByteUnpacker.ReadValueBitPacked(reader, out uint bitFlagsState);
+ // Test the deserialized values match the original values
+ var deserializedState = new NetworkTransformState();
+ // Set the flags
+ deserializedState.FlagStates.SetFlags(bitFlagsState);
+
+ Array.Fill(boolSet, true);
+ AssertTransformStateEquals(boolSet, deserializedState, "Read bitset");
+ }
+
+ private void AssertTransformStateEquals(bool[] expected, NetworkTransformState actual, string testName)
+ {
+ Assert.AreEqual(expected[0], actual.FlagStates.InLocalSpace, $"{testName} Flag {nameof(FlagStates.InLocalSpace)} is incorrect!");
+ Assert.AreEqual(expected[1], actual.FlagStates.HasPositionX, $"{testName} Flag {nameof(FlagStates.HasPositionX)} is incorrect!");
+ Assert.AreEqual(expected[2], actual.FlagStates.HasPositionY, $"{testName} Flag {nameof(FlagStates.HasPositionY)} is incorrect!");
+ Assert.AreEqual(expected[3], actual.FlagStates.HasPositionZ, $"{testName} Flag {nameof(FlagStates.HasPositionZ)} is incorrect!");
+ Assert.AreEqual(expected[4], actual.FlagStates.HasRotAngleX, $"{testName} Flag {nameof(FlagStates.HasRotAngleX)} is incorrect!");
+ Assert.AreEqual(expected[5], actual.FlagStates.HasRotAngleY, $"{testName} Flag {nameof(FlagStates.HasRotAngleY)} is incorrect!");
+ Assert.AreEqual(expected[6], actual.FlagStates.HasRotAngleZ, $"{testName} Flag {nameof(FlagStates.HasRotAngleZ)} is incorrect!");
+ Assert.AreEqual(expected[7], actual.FlagStates.HasScaleX, $"{testName} Flag {nameof(FlagStates.HasScaleX)} is incorrect!");
+ Assert.AreEqual(expected[8], actual.FlagStates.HasScaleY, $"{testName} Flag {nameof(FlagStates.HasScaleY)} is incorrect!");
+ Assert.AreEqual(expected[9], actual.FlagStates.HasScaleZ, $"{testName} Flag {nameof(FlagStates.HasScaleZ)} is incorrect!");
+ Assert.AreEqual(expected[10], actual.FlagStates.IsTeleportingNextFrame, $"{testName} Flag {nameof(FlagStates.IsTeleportingNextFrame)} is incorrect!");
+ Assert.AreEqual(expected[11], actual.FlagStates.UseInterpolation, $"{testName} Flag {nameof(FlagStates.UseInterpolation)} is incorrect!");
+ Assert.AreEqual(expected[12], actual.FlagStates.QuaternionSync, $"{testName} Flag {nameof(FlagStates.QuaternionSync)} is incorrect!");
+ Assert.AreEqual(expected[13], actual.FlagStates.QuaternionCompression, $"{testName} Flag {nameof(FlagStates.QuaternionCompression)} is incorrect!");
+ Assert.AreEqual(expected[14], actual.FlagStates.UseHalfFloatPrecision, $"{testName} Flag {nameof(FlagStates.UseHalfFloatPrecision)} is incorrect!");
+ Assert.AreEqual(expected[15], actual.FlagStates.IsSynchronizing, $"{testName} Flag {nameof(FlagStates.IsSynchronizing)} is incorrect!");
+ Assert.AreEqual(expected[16], actual.FlagStates.UsePositionSlerp, $"{testName} Flag {nameof(FlagStates.UsePositionSlerp)} is incorrect!");
+ Assert.AreEqual(expected[17], actual.FlagStates.IsParented, $"{testName} Flag {nameof(FlagStates.IsParented)} is incorrect!");
+ Assert.AreEqual(expected[18], actual.FlagStates.SynchronizeBaseHalfFloat, $"{testName} Flag {nameof(FlagStates.SynchronizeBaseHalfFloat)} is incorrect!");
+ Assert.AreEqual(expected[19], actual.FlagStates.ReliableSequenced, $"{testName} Flag {nameof(FlagStates.ReliableSequenced)} is incorrect!");
+ Assert.AreEqual(expected[20], actual.FlagStates.UseUnreliableDeltas, $"{testName} Flag {nameof(FlagStates.UseUnreliableDeltas)} is incorrect!");
+ Assert.AreEqual(expected[21], actual.FlagStates.UnreliableFrameSync, $"{testName} Flag {nameof(FlagStates.UnreliableFrameSync)} is incorrect!");
+ Assert.AreEqual(expected[22], actual.FlagStates.SwitchTransformSpaceWhenParented, $"{testName} Flag {nameof(FlagStates.SwitchTransformSpaceWhenParented)} is incorrect!");
+ Assert.AreEqual(expected[23], actual.FlagStates.TrackByStateId, $"{testName} Flag {nameof(FlagStates.TrackByStateId)} is incorrect!");
+ }
+
+ }
+
+ // These tests do not need to run against the Rust server.
+ [IgnoreIfServiceEnvironmentVariableSet]
[TestFixture(TransformSpace.World, Precision.Full, Rotation.Euler)]
[TestFixture(TransformSpace.World, Precision.Half, Rotation.Euler)]
[TestFixture(TransformSpace.Local, Precision.Full, Rotation.Euler)]
@@ -15,7 +207,7 @@ namespace Unity.Netcode.RuntimeTests
[TestFixture(TransformSpace.World, Precision.Half, Rotation.Quaternion)]
[TestFixture(TransformSpace.Local, Precision.Full, Rotation.Quaternion)]
[TestFixture(TransformSpace.Local, Precision.Half, Rotation.Quaternion)]
- internal class NetworkTransformStateTests
+ internal class NetworkTransformStateConfigurationTests
{
public enum SyncAxis
{
@@ -77,14 +269,7 @@ public enum Precision
private Precision m_Precision;
private Rotation m_Rotation;
- [OneTimeSetUp]
- public void OneTimeSetup()
- {
- // This test does not need to run against the Rust server.
- NetcodeIntegrationTestHelpers.IgnoreIfServiceEnviromentVariableSet();
- }
-
- public NetworkTransformStateTests(TransformSpace transformSpace, Precision precision, Rotation rotation)
+ public NetworkTransformStateConfigurationTests(TransformSpace transformSpace, Precision precision, Rotation rotation)
{
m_TransformSpace = transformSpace;
m_Precision = precision;
@@ -98,125 +283,6 @@ private bool WillAnAxisBeSynchronized(ref NetworkTransform networkTransform)
networkTransform.SyncPositionX || networkTransform.SyncPositionY || networkTransform.SyncPositionZ;
}
- [Test]
- public void NetworkTransformStateFlags()
- {
- var indexValues = new System.Collections.Generic.List();
- var currentFlag = (uint)0x00000001;
- for (int j = 0; j < 18; j++)
- {
- indexValues.Add(currentFlag);
- currentFlag = currentFlag << 1;
- }
-
- // TrackByStateId is unique
- indexValues.Add(0x10000000);
-
- var boolSet = new System.Collections.Generic.List();
- var transformState = new NetworkTransform.NetworkTransformState();
- // Test setting one at a time.
- for (int j = 0; j < 19; j++)
- {
- boolSet = new System.Collections.Generic.List();
- for (int i = 0; i < 19; i++)
- {
- if (i == j)
- {
- boolSet.Add(true);
- }
- else
- {
- boolSet.Add(false);
- }
- }
- transformState = new NetworkTransform.NetworkTransformState()
- {
- InLocalSpace = boolSet[0],
- HasPositionX = boolSet[1],
- HasPositionY = boolSet[2],
- HasPositionZ = boolSet[3],
- HasRotAngleX = boolSet[4],
- HasRotAngleY = boolSet[5],
- HasRotAngleZ = boolSet[6],
- HasScaleX = boolSet[7],
- HasScaleY = boolSet[8],
- HasScaleZ = boolSet[9],
- IsTeleportingNextFrame = boolSet[10],
- UseInterpolation = boolSet[11],
- QuaternionSync = boolSet[12],
- QuaternionCompression = boolSet[13],
- UseHalfFloatPrecision = boolSet[14],
- IsSynchronizing = boolSet[15],
- UsePositionSlerp = boolSet[16],
- IsParented = boolSet[17],
- TrackByStateId = boolSet[18],
- };
- Assert.True((transformState.BitSet & indexValues[j]) == indexValues[j], $"[FlagTest][Individual] Set flag value {indexValues[j]} at index {j}, but BitSet value did not match!");
- }
-
- // Test setting all flag values
- boolSet = new System.Collections.Generic.List();
- for (int i = 0; i < 19; i++)
- {
- boolSet.Add(true);
- }
-
- transformState = new NetworkTransform.NetworkTransformState()
- {
- InLocalSpace = boolSet[0],
- HasPositionX = boolSet[1],
- HasPositionY = boolSet[2],
- HasPositionZ = boolSet[3],
- HasRotAngleX = boolSet[4],
- HasRotAngleY = boolSet[5],
- HasRotAngleZ = boolSet[6],
- HasScaleX = boolSet[7],
- HasScaleY = boolSet[8],
- HasScaleZ = boolSet[9],
- IsTeleportingNextFrame = boolSet[10],
- UseInterpolation = boolSet[11],
- QuaternionSync = boolSet[12],
- QuaternionCompression = boolSet[13],
- UseHalfFloatPrecision = boolSet[14],
- IsSynchronizing = boolSet[15],
- UsePositionSlerp = boolSet[16],
- IsParented = boolSet[17],
- TrackByStateId = boolSet[18],
- };
-
- for (int j = 0; j < 19; j++)
- {
- Assert.True((transformState.BitSet & indexValues[j]) == indexValues[j], $"[FlagTest][All] All flag values are set but failed to detect flag value {indexValues[j]}!");
- }
-
- // Test getting all flag values
- transformState = new NetworkTransform.NetworkTransformState();
- for (int i = 0; i < 19; i++)
- {
- transformState.BitSet |= indexValues[i];
- }
-
- Assert.True(transformState.InLocalSpace, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.InLocalSpace)}!");
- Assert.True(transformState.HasPositionX, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasPositionX)}!");
- Assert.True(transformState.HasPositionY, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasPositionY)}!");
- Assert.True(transformState.HasPositionZ, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasPositionZ)}!");
- Assert.True(transformState.HasRotAngleX, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasRotAngleX)}!");
- Assert.True(transformState.HasRotAngleY, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasRotAngleY)}!");
- Assert.True(transformState.HasRotAngleZ, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasRotAngleZ)}!");
- Assert.True(transformState.HasScaleX, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasScaleX)}!");
- Assert.True(transformState.HasScaleY, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasScaleY)}!");
- Assert.True(transformState.HasScaleZ, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.HasScaleZ)}!");
- Assert.True(transformState.IsTeleportingNextFrame, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.IsTeleportingNextFrame)}!");
- Assert.True(transformState.UseInterpolation, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.UseInterpolation)}!");
- Assert.True(transformState.QuaternionSync, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.QuaternionSync)}!");
- Assert.True(transformState.QuaternionCompression, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.QuaternionCompression)}!");
- Assert.True(transformState.UseHalfFloatPrecision, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.UseHalfFloatPrecision)}!");
- Assert.True(transformState.IsSynchronizing, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.IsSynchronizing)}!");
- Assert.True(transformState.UsePositionSlerp, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.UsePositionSlerp)}!");
- Assert.True(transformState.IsParented, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.IsParented)}!");
- Assert.True(transformState.TrackByStateId, $"[FlagTest][Get] Failed to detect {nameof(NetworkTransform.NetworkTransformState.TrackByStateId)}!");
- }
-
[Test]
public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Values] SyncAxis syncAxis)
@@ -269,10 +335,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// We want a relatively clean networkTransform state before we try to apply the transform to it
// We only preserve InLocalSpace and IsTeleportingNextFrame properties as they are the only things
// needed when applying a transform to a NetworkTransformState
- var networkTransformState = new NetworkTransform.NetworkTransformState
+ var networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
NetworkDeltaPosition = new NetworkDeltaPosition(Vector3.zero, 0)
};
@@ -291,10 +360,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ }
};
var position = networkTransform.transform.position;
var rotAngles = networkTransform.transform.eulerAngles;
@@ -305,10 +377,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// axis deltas that happened over a tick as a collection instead of collapsing them
// as the changes are detected.
{
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ }
};
// SyncPositionX
@@ -439,10 +514,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ }
};
position = networkTransform.transform.position;
@@ -473,10 +551,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ }
};
// SyncPositionY
if (syncPosY)
@@ -489,10 +570,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasPositionY);
@@ -505,10 +589,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncPositionZ
if (syncPosZ)
@@ -521,10 +608,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasPositionZ);
@@ -537,10 +627,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncRotAngleX - Now test that we don't synchronize this specific axis as long as we are not using quaternion synchronization
if (syncRotX && m_Rotation == Rotation.Euler)
@@ -553,10 +646,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasRotAngleX);
@@ -569,10 +665,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncRotAngleY - Now test that we don't synchronize this specific axis as long as we are not using quaternion synchronization
if (syncRotY && m_Rotation == Rotation.Euler)
@@ -585,10 +684,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasRotAngleY);
@@ -601,10 +703,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncRotAngleZ - Now test that we don't synchronize this specific axis as long as we are not using quaternion synchronization
if (syncRotZ && m_Rotation == Rotation.Euler)
@@ -617,10 +722,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasRotAngleZ);
@@ -633,10 +741,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncScaleX
if (syncScaX)
@@ -649,10 +760,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasScaleX);
@@ -665,10 +779,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncScaleY
if (syncScaY)
@@ -681,10 +798,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasScaleY);
@@ -697,10 +817,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
// Reset the NetworkTransformState since teleporting will preserve
// any dirty values
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ },
};
// SyncScaleZ
if (syncScaZ)
@@ -713,10 +836,13 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
{
// We want to start with a fresh NetworkTransformState since it could have other state
// information from the last time we applied the transform
- networkTransformState = new NetworkTransform.NetworkTransformState
+ networkTransformState = new NetworkTransformState
{
- InLocalSpace = inLocalSpace,
- IsTeleportingNextFrame = isTeleporting,
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ IsTeleportingNextFrame = isTeleporting,
+ }
};
Assert.IsTrue(networkTransform.ApplyTransformToNetworkState(ref networkTransformState, 0, networkTransform.transform));
Assert.IsFalse(networkTransformState.HasScaleZ);
@@ -736,9 +862,9 @@ public void TestSyncAxes([Values] SynchronizationType synchronizationType, [Valu
[Test]
public void TestThresholds(
- [Values(NetworkTransform.PositionThresholdDefault, 1.0f)] float positionThreshold,
- [Values(NetworkTransform.RotAngleThresholdDefault, 1.0f)] float rotAngleThreshold,
- [Values(NetworkTransform.ScaleThresholdDefault, 0.5f)] float scaleThreshold)
+ [Values(PositionThresholdDefault, 1.0f)] float positionThreshold,
+ [Values(RotAngleThresholdDefault, 1.0f)] float rotAngleThreshold,
+ [Values(ScaleThresholdDefault, 0.5f)] float scaleThreshold)
{
var inLocalSpace = m_TransformSpace == TransformSpace.Local;
var gameObject = new GameObject($"Test-{nameof(NetworkTransformStateTests)}.{nameof(TestThresholds)}");
@@ -766,7 +892,7 @@ public void TestThresholds(
networkTransform.RotAngleThreshold = rotAngleThreshold;
networkTransform.ScaleThreshold = scaleThreshold;
- var networkTransformState = new NetworkTransform.NetworkTransformState
+ var networkTransformState = new NetworkTransformState
{
PositionX = initialPosition.x,
PositionY = initialPosition.y,
@@ -777,7 +903,10 @@ public void TestThresholds(
ScaleX = initialScale.x,
ScaleY = initialScale.y,
ScaleZ = initialScale.z,
- InLocalSpace = inLocalSpace
+ FlagStates = new FlagStates()
+ {
+ InLocalSpace = inLocalSpace,
+ },
};
// Step 1: change properties, expect state to be dirty
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions.meta b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions.meta
new file mode 100644
index 0000000000..6313602724
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d44194b68d19479ab0a4427dc5211591
+timeCreated: 1757013308
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs
new file mode 100644
index 0000000000..8f48a20666
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs
@@ -0,0 +1,26 @@
+using System;
+using NUnit.Framework;
+using NUnit.Framework.Interfaces;
+using NUnit.Framework.Internal;
+
+namespace Unity.Netcode.TestHelpers.Runtime
+{
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+ internal class IgnoreIfServiceEnvironmentVariableSetAttribute : NUnitAttribute, IApplyToTest
+ {
+ public void ApplyToTest(Test test)
+ {
+ // NotRunnable is the more weighty status, always respect it first
+ if (test.RunState == RunState.NotRunnable)
+ {
+ return;
+ }
+
+ if (bool.TryParse(NetcodeIntegrationTestHelpers.GetCMBServiceEnvironentVariable(), out var isTrue) && isTrue)
+ {
+ test.RunState = RunState.Ignored;
+ test.Properties.Set("_SKIPREASON", NetcodeIntegrationTestHelpers.IgnoredForCmbServiceReason);
+ }
+ }
+ }
+}
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs.meta
new file mode 100644
index 0000000000..c4efe43d74
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NUnitExtensions/IgnoreIfServiceEnvironmentVariableSetAttribute.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d27ee61f70254bc68185f63867a8dd3f
+timeCreated: 1757013351
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs
index c8e40ae256..d09d1da9b6 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs
@@ -201,6 +201,8 @@ internal static string GetCMBServiceEnvironentVariable()
#endif
}
+ internal static readonly string IgnoredForCmbServiceReason = "[CMB-Service Test Run] Skipping non-distributed authority test.";
+
///
/// Use for non derived integration tests to automatically ignore the
/// test if running against a CMB server.
@@ -209,7 +211,7 @@ internal static void IgnoreIfServiceEnviromentVariableSet()
{
if (bool.TryParse(GetCMBServiceEnvironentVariable(), out bool isTrue) ? isTrue : false)
{
- Assert.Ignore("[CMB-Server Test Run] Skipping non-distributed authority test.");
+ Assert.Ignore(IgnoredForCmbServiceReason);
}
}