com.unity.netcode.gameobjects@1.0.0-pre.8
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.0.0-pre.8] - 2022-04-27 ### Changed - `unmanaged` structs are no longer universally accepted as RPC parameters because some structs (i.e., structs with pointers in them, such as `NativeList<T>`) can't be supported by the default memcpy struct serializer. Structs that are intended to be serialized across the network must add `INetworkSerializeByMemcpy` to the interface list (i.e., `struct Foo : INetworkSerializeByMemcpy`). This interface is empty and just serves to mark the struct as compatible with memcpy serialization. For external structs you can't edit, you can pass them to RPCs by wrapping them in `ForceNetworkSerializeByMemcpy<T>`. (#1901) ### Removed - Removed `SIPTransport` (#1870) - Removed `ClientNetworkTransform` from the package samples and moved to Boss Room's Utilities package which can be found [here](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/main/Packages/com.unity.multiplayer.samples.coop/Utilities/Net/ClientAuthority/ClientNetworkTransform.cs). ### Fixed - Fixed `NetworkTransform` generating false positive rotation delta checks when rolling over between 0 and 360 degrees. (#1890) - Fixed client throwing an exception if it has messages in the outbound queue when processing the `NetworkEvent.Disconnect` event and is using UTP. (#1884) - Fixed issue during client synchronization if 'ValidateSceneBeforeLoading' returned false it would halt the client synchronization process resulting in a client that was approved but not synchronized or fully connected with the server. (#1883) - Fixed an issue where UNetTransport.StartServer would return success even if the underlying transport failed to start (#854) - Passing generic types to RPCs no longer causes a native crash (#1901) - Fixed an issue where calling `Shutdown` on a `NetworkManager` that was already shut down would cause an immediate shutdown the next time it was started (basically the fix makes `Shutdown` idempotent). (#1877)
This commit is contained in:
@@ -4,13 +4,11 @@ using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Solves for incoming values that are jittered
|
||||
/// Partially solves for message loss. Unclamped lerping helps hide this, but not completely
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal abstract class BufferedLinearInterpolator<T> where T : struct
|
||||
public abstract class BufferedLinearInterpolator<T> where T : struct
|
||||
{
|
||||
private struct BufferedItem
|
||||
{
|
||||
@@ -24,6 +22,10 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// There’s two factors affecting interpolation: buffering (set in NetworkManager’s NetworkTimeSystem) and interpolation time, which is the amount of time it’ll take to reach the target. This is to affect the second one.
|
||||
/// </summary>
|
||||
public float MaximumInterpolationTime = 0.1f;
|
||||
|
||||
private const double k_SmallValue = 9.999999439624929E-11; // copied from Vector3's equal operator
|
||||
|
||||
@@ -69,6 +71,9 @@ namespace Unity.Netcode
|
||||
|
||||
private bool InvalidState => m_Buffer.Count == 0 && m_LifetimeConsumedCount == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Resets Interpolator to initial state
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_Buffer.Clear();
|
||||
@@ -76,6 +81,9 @@ namespace Unity.Netcode
|
||||
m_StartTimeConsumed = 0.0d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports current interpolation value to targetValue.
|
||||
/// </summary>
|
||||
public void ResetTo(T targetValue, double serverTime)
|
||||
{
|
||||
m_LifetimeConsumedCount = 1;
|
||||
@@ -89,7 +97,6 @@ namespace Unity.Netcode
|
||||
Update(0, serverTime, serverTime);
|
||||
}
|
||||
|
||||
|
||||
// todo if I have value 1, 2, 3 and I'm treating 1 to 3, I shouldn't interpolate between 1 and 3, I should interpolate from 1 to 2, then from 2 to 3 to get the best path
|
||||
private void TryConsumeFromBuffer(double renderTime, double serverTime)
|
||||
{
|
||||
@@ -205,14 +212,16 @@ namespace Unity.Netcode
|
||||
}
|
||||
|
||||
var target = InterpolateUnclamped(m_InterpStartValue, m_InterpEndValue, t);
|
||||
float maxInterpTime = 0.1f;
|
||||
m_CurrentInterpValue = Interpolate(m_CurrentInterpValue, target, deltaTime / maxInterpTime); // second interpolate to smooth out extrapolation jumps
|
||||
m_CurrentInterpValue = Interpolate(m_CurrentInterpValue, target, deltaTime / MaximumInterpolationTime); // second interpolate to smooth out extrapolation jumps
|
||||
}
|
||||
|
||||
m_NbItemsReceivedThisFrame = 0;
|
||||
return m_CurrentInterpValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add measurements to be used during interpolation. These will be buffered before being made available to be displayed as "latest value".
|
||||
/// </summary>
|
||||
public void AddMeasurement(T newMeasurement, double sentTime)
|
||||
{
|
||||
m_NbItemsReceivedThisFrame++;
|
||||
@@ -239,17 +248,25 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets latest value from the interpolator. This is updated every update as time goes by.
|
||||
/// </summary>
|
||||
public T GetInterpolatedValue()
|
||||
{
|
||||
return m_CurrentInterpValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to override and adapted to the generic type. This assumes interpolation for that value will be clamped.
|
||||
/// </summary>
|
||||
protected abstract T Interpolate(T start, T end, float time);
|
||||
/// <summary>
|
||||
/// Method to override and adapted to the generic type. This assumes interpolation for that value will not be clamped.
|
||||
/// </summary>
|
||||
protected abstract T InterpolateUnclamped(T start, T end, float time);
|
||||
}
|
||||
|
||||
|
||||
internal class BufferedLinearInterpolatorFloat : BufferedLinearInterpolator<float>
|
||||
public class BufferedLinearInterpolatorFloat : BufferedLinearInterpolator<float>
|
||||
{
|
||||
protected override float InterpolateUnclamped(float start, float end, float time)
|
||||
{
|
||||
@@ -262,7 +279,7 @@ namespace Unity.Netcode
|
||||
}
|
||||
}
|
||||
|
||||
internal class BufferedLinearInterpolatorQuaternion : BufferedLinearInterpolator<Quaternion>
|
||||
public class BufferedLinearInterpolatorQuaternion : BufferedLinearInterpolator<Quaternion>
|
||||
{
|
||||
protected override Quaternion InterpolateUnclamped(Quaternion start, Quaternion end, float time)
|
||||
{
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace Unity.Netcode.Components
|
||||
internal struct AnimationMessage : INetworkSerializable
|
||||
{
|
||||
// state hash per layer. if non-zero, then Play() this animation, skipping transitions
|
||||
public int StateHash;
|
||||
public float NormalizedTime;
|
||||
public int Layer;
|
||||
public float Weight;
|
||||
public byte[] Parameters;
|
||||
internal int StateHash;
|
||||
internal float NormalizedTime;
|
||||
internal int Layer;
|
||||
internal float Weight;
|
||||
internal byte[] Parameters;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
@@ -33,8 +33,8 @@ namespace Unity.Netcode.Components
|
||||
|
||||
internal struct AnimationTriggerMessage : INetworkSerializable
|
||||
{
|
||||
public int Hash;
|
||||
public bool Reset;
|
||||
internal int Hash;
|
||||
internal bool Reset;
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
|
||||
{
|
||||
@@ -57,7 +57,7 @@ namespace Unity.Netcode.Components
|
||||
private bool m_SendMessagesAllowed = false;
|
||||
|
||||
// Animators only support up to 32 params
|
||||
public static int K_MaxAnimationParams = 32;
|
||||
private const int k_MaxAnimationParams = 32;
|
||||
|
||||
private int[] m_TransitionHash;
|
||||
private int[] m_AnimationHash;
|
||||
@@ -65,21 +65,21 @@ namespace Unity.Netcode.Components
|
||||
|
||||
private unsafe struct AnimatorParamCache
|
||||
{
|
||||
public int Hash;
|
||||
public int Type;
|
||||
public fixed byte Value[4]; // this is a max size of 4 bytes
|
||||
internal int Hash;
|
||||
internal int Type;
|
||||
internal fixed byte Value[4]; // this is a max size of 4 bytes
|
||||
}
|
||||
|
||||
// 128 bytes per Animator
|
||||
private FastBufferWriter m_ParameterWriter = new FastBufferWriter(K_MaxAnimationParams * sizeof(float), Allocator.Persistent);
|
||||
private FastBufferWriter m_ParameterWriter = new FastBufferWriter(k_MaxAnimationParams * sizeof(float), Allocator.Persistent);
|
||||
private NativeArray<AnimatorParamCache> m_CachedAnimatorParameters;
|
||||
|
||||
// We cache these values because UnsafeUtility.EnumToInt uses direct IL that allows a non-boxing conversion
|
||||
private struct AnimationParamEnumWrapper
|
||||
{
|
||||
public static readonly int AnimatorControllerParameterInt;
|
||||
public static readonly int AnimatorControllerParameterFloat;
|
||||
public static readonly int AnimatorControllerParameterBool;
|
||||
internal static readonly int AnimatorControllerParameterInt;
|
||||
internal static readonly int AnimatorControllerParameterFloat;
|
||||
internal static readonly int AnimatorControllerParameterBool;
|
||||
|
||||
static AnimationParamEnumWrapper()
|
||||
{
|
||||
|
||||
@@ -5,77 +5,97 @@ namespace Unity.Netcode.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// NetworkRigidbody allows for the use of <see cref="Rigidbody"/> on network objects. By controlling the kinematic
|
||||
/// mode of the rigidbody and disabling it on all peers but the authoritative one.
|
||||
/// mode of the <see cref="Rigidbody"/> and disabling it on all peers but the authoritative one.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Rigidbody))]
|
||||
[RequireComponent(typeof(NetworkTransform))]
|
||||
public class NetworkRigidbody : NetworkBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines if we are server (true) or owner (false) authoritative
|
||||
/// </summary>
|
||||
private bool m_IsServerAuthoritative;
|
||||
|
||||
private Rigidbody m_Rigidbody;
|
||||
private NetworkTransform m_NetworkTransform;
|
||||
|
||||
private bool m_OriginalKinematic;
|
||||
private RigidbodyInterpolation m_OriginalInterpolation;
|
||||
|
||||
// Used to cache the authority state of this rigidbody during the last frame
|
||||
// Used to cache the authority state of this Rigidbody during the last frame
|
||||
private bool m_IsAuthority;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a bool value indicating whether this <see cref="NetworkRigidbody"/> on this peer currently holds authority.
|
||||
/// </summary>
|
||||
private bool HasAuthority => m_NetworkTransform.CanCommitToTransform;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_Rigidbody = GetComponent<Rigidbody>();
|
||||
m_NetworkTransform = GetComponent<NetworkTransform>();
|
||||
m_IsServerAuthoritative = m_NetworkTransform.IsServerAuthoritative();
|
||||
|
||||
m_Rigidbody = GetComponent<Rigidbody>();
|
||||
m_OriginalInterpolation = m_Rigidbody.interpolation;
|
||||
|
||||
// Set interpolation to none if NetworkTransform is handling interpolation, otherwise it sets it to the original value
|
||||
m_Rigidbody.interpolation = m_NetworkTransform.Interpolate ? RigidbodyInterpolation.None : m_OriginalInterpolation;
|
||||
|
||||
// Turn off physics for the rigid body until spawned, otherwise
|
||||
// clients can run fixed update before the first full
|
||||
// NetworkTransform update
|
||||
m_Rigidbody.isKinematic = true;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
/// <summary>
|
||||
/// For owner authoritative (i.e. ClientNetworkTransform)
|
||||
/// we adjust our authority when we gain ownership
|
||||
/// </summary>
|
||||
public override void OnGainedOwnership()
|
||||
{
|
||||
if (NetworkManager.IsListening)
|
||||
{
|
||||
if (HasAuthority != m_IsAuthority)
|
||||
{
|
||||
m_IsAuthority = HasAuthority;
|
||||
UpdateRigidbodyKinematicMode();
|
||||
}
|
||||
}
|
||||
UpdateOwnershipAuthority();
|
||||
}
|
||||
|
||||
// Puts the rigidbody in a kinematic non-interpolated mode on everyone but the server.
|
||||
private void UpdateRigidbodyKinematicMode()
|
||||
/// <summary>
|
||||
/// For owner authoritative(i.e. ClientNetworkTransform)
|
||||
/// we adjust our authority when we have lost ownership
|
||||
/// </summary>
|
||||
public override void OnLostOwnership()
|
||||
{
|
||||
if (m_IsAuthority == false)
|
||||
{
|
||||
m_OriginalKinematic = m_Rigidbody.isKinematic;
|
||||
m_Rigidbody.isKinematic = true;
|
||||
UpdateOwnershipAuthority();
|
||||
}
|
||||
|
||||
m_OriginalInterpolation = m_Rigidbody.interpolation;
|
||||
// Set interpolation to none, the NetworkTransform component interpolates the position of the object.
|
||||
m_Rigidbody.interpolation = RigidbodyInterpolation.None;
|
||||
/// <summary>
|
||||
/// Sets the authority differently depending upon
|
||||
/// whether it is server or owner authoritative
|
||||
/// </summary>
|
||||
private void UpdateOwnershipAuthority()
|
||||
{
|
||||
if (m_IsServerAuthoritative)
|
||||
{
|
||||
m_IsAuthority = NetworkManager.IsServer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resets the rigidbody back to it's non replication only state. Happens on shutdown and when authority is lost
|
||||
m_Rigidbody.isKinematic = m_OriginalKinematic;
|
||||
m_Rigidbody.interpolation = m_OriginalInterpolation;
|
||||
m_IsAuthority = IsOwner;
|
||||
}
|
||||
|
||||
// If you have authority then you are not kinematic
|
||||
m_Rigidbody.isKinematic = !m_IsAuthority;
|
||||
|
||||
// Set interpolation of the Rigidbody based on authority
|
||||
// With authority: let local transform handle interpolation
|
||||
// Without authority: let the NetworkTransform handle interpolation
|
||||
m_Rigidbody.interpolation = m_IsAuthority ? m_OriginalInterpolation : RigidbodyInterpolation.None;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
m_IsAuthority = HasAuthority;
|
||||
m_OriginalKinematic = m_Rigidbody.isKinematic;
|
||||
m_OriginalInterpolation = m_Rigidbody.interpolation;
|
||||
UpdateRigidbodyKinematicMode();
|
||||
UpdateOwnershipAuthority();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
UpdateRigidbodyKinematicMode();
|
||||
m_Rigidbody.interpolation = m_OriginalInterpolation;
|
||||
// Turn off physics for the rigid body until spawned, otherwise
|
||||
// non-owners can run fixed updates before the first full
|
||||
// NetworkTransform update and physics will be applied (i.e. gravity, etc)
|
||||
m_Rigidbody.isKinematic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,10 @@ namespace Unity.Netcode.Components
|
||||
[DefaultExecutionOrder(100000)] // this is needed to catch the update time after the transform was updated by user scripts
|
||||
public class NetworkTransform : NetworkBehaviour
|
||||
{
|
||||
public const float PositionThresholdDefault = .001f;
|
||||
public const float RotAngleThresholdDefault = .01f;
|
||||
public const float ScaleThresholdDefault = .01f;
|
||||
public const float PositionThresholdDefault = 0.001f;
|
||||
public const float RotAngleThresholdDefault = 0.01f;
|
||||
public const float ScaleThresholdDefault = 0.01f;
|
||||
|
||||
public delegate (Vector3 pos, Quaternion rotOut, Vector3 scale) OnClientRequestChangeDelegate(Vector3 pos, Quaternion rot, Vector3 scale);
|
||||
public OnClientRequestChangeDelegate OnClientRequestChange;
|
||||
|
||||
@@ -38,7 +39,7 @@ namespace Unity.Netcode.Components
|
||||
// 11-15: <unused>
|
||||
private ushort m_Bitset;
|
||||
|
||||
public bool InLocalSpace
|
||||
internal bool InLocalSpace
|
||||
{
|
||||
get => (m_Bitset & (1 << k_InLocalSpaceBit)) != 0;
|
||||
set
|
||||
@@ -49,7 +50,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
// Position
|
||||
public bool HasPositionX
|
||||
internal bool HasPositionX
|
||||
{
|
||||
get => (m_Bitset & (1 << k_PositionXBit)) != 0;
|
||||
set
|
||||
@@ -59,7 +60,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasPositionY
|
||||
internal bool HasPositionY
|
||||
{
|
||||
get => (m_Bitset & (1 << k_PositionYBit)) != 0;
|
||||
set
|
||||
@@ -69,7 +70,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasPositionZ
|
||||
internal bool HasPositionZ
|
||||
{
|
||||
get => (m_Bitset & (1 << k_PositionZBit)) != 0;
|
||||
set
|
||||
@@ -80,7 +81,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
// RotAngles
|
||||
public bool HasRotAngleX
|
||||
internal bool HasRotAngleX
|
||||
{
|
||||
get => (m_Bitset & (1 << k_RotAngleXBit)) != 0;
|
||||
set
|
||||
@@ -90,7 +91,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasRotAngleY
|
||||
internal bool HasRotAngleY
|
||||
{
|
||||
get => (m_Bitset & (1 << k_RotAngleYBit)) != 0;
|
||||
set
|
||||
@@ -100,7 +101,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasRotAngleZ
|
||||
internal bool HasRotAngleZ
|
||||
{
|
||||
get => (m_Bitset & (1 << k_RotAngleZBit)) != 0;
|
||||
set
|
||||
@@ -111,7 +112,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
// Scale
|
||||
public bool HasScaleX
|
||||
internal bool HasScaleX
|
||||
{
|
||||
get => (m_Bitset & (1 << k_ScaleXBit)) != 0;
|
||||
set
|
||||
@@ -121,7 +122,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasScaleY
|
||||
internal bool HasScaleY
|
||||
{
|
||||
get => (m_Bitset & (1 << k_ScaleYBit)) != 0;
|
||||
set
|
||||
@@ -131,7 +132,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasScaleZ
|
||||
internal bool HasScaleZ
|
||||
{
|
||||
get => (m_Bitset & (1 << k_ScaleZBit)) != 0;
|
||||
set
|
||||
@@ -141,7 +142,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsTeleportingNextFrame
|
||||
internal bool IsTeleportingNextFrame
|
||||
{
|
||||
get => (m_Bitset & (1 << k_TeleportingBit)) != 0;
|
||||
set
|
||||
@@ -151,12 +152,12 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public float PositionX, PositionY, PositionZ;
|
||||
public float RotAngleX, RotAngleY, RotAngleZ;
|
||||
public float ScaleX, ScaleY, ScaleZ;
|
||||
public double SentTime;
|
||||
internal float PositionX, PositionY, PositionZ;
|
||||
internal float RotAngleX, RotAngleY, RotAngleZ;
|
||||
internal float ScaleX, ScaleY, ScaleZ;
|
||||
internal double SentTime;
|
||||
|
||||
public Vector3 Position
|
||||
internal Vector3 Position
|
||||
{
|
||||
get { return new Vector3(PositionX, PositionY, PositionZ); }
|
||||
set
|
||||
@@ -167,7 +168,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Rotation
|
||||
internal Vector3 Rotation
|
||||
{
|
||||
get { return new Vector3(RotAngleX, RotAngleY, RotAngleZ); }
|
||||
set
|
||||
@@ -178,7 +179,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Scale
|
||||
internal Vector3 Scale
|
||||
{
|
||||
get { return new Vector3(ScaleX, ScaleY, ScaleZ); }
|
||||
set
|
||||
@@ -249,7 +250,10 @@ namespace Unity.Netcode.Components
|
||||
public bool SyncScaleX = true, SyncScaleY = true, SyncScaleZ = true;
|
||||
|
||||
public float PositionThreshold = PositionThresholdDefault;
|
||||
|
||||
[Range(0.001f, 360.0f)]
|
||||
public float RotAngleThreshold = RotAngleThresholdDefault;
|
||||
|
||||
public float ScaleThreshold = ScaleThresholdDefault;
|
||||
|
||||
/// <summary>
|
||||
@@ -280,8 +284,6 @@ namespace Unity.Netcode.Components
|
||||
|
||||
private NetworkTransformState m_LocalAuthoritativeNetworkState;
|
||||
|
||||
private NetworkTransformState m_PrevNetworkState;
|
||||
|
||||
private const int k_DebugDrawLineTime = 10;
|
||||
|
||||
private bool m_HasSentLastValue = false; // used to send one last value, so clients can make the difference between lost replication data (clients extrapolate) and no more data to send.
|
||||
@@ -390,6 +392,16 @@ namespace Unity.Netcode.Components
|
||||
m_ScaleZInterpolator.ResetTo(m_LocalAuthoritativeNetworkState.ScaleZ, serverTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will apply the transform to the LocalAuthoritativeNetworkState and get detailed isDirty information returned.
|
||||
/// </summary>
|
||||
/// <param name="transform">transform to apply</param>
|
||||
/// <returns>bool isDirty, bool isPositionDirty, bool isRotationDirty, bool isScaleDirty</returns>
|
||||
internal (bool isDirty, bool isPositionDirty, bool isRotationDirty, bool isScaleDirty) ApplyLocalNetworkState(Transform transform)
|
||||
{
|
||||
return ApplyTransformToNetworkStateWithInfo(ref m_LocalAuthoritativeNetworkState, m_CachedNetworkManager.LocalTime.Time, transform);
|
||||
}
|
||||
|
||||
// updates `NetworkState` properties if they need to and returns a `bool` indicating whether or not there was any changes made
|
||||
// returned boolean would be useful to change encapsulating `NetworkVariable<NetworkState>`'s dirty state, e.g. ReplNetworkState.SetDirty(isDirty);
|
||||
internal bool ApplyTransformToNetworkState(ref NetworkTransformState networkState, double dirtyTime, Transform transformToUse)
|
||||
@@ -450,7 +462,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
if (SyncRotAngleX &&
|
||||
Mathf.Abs(networkState.RotAngleX - rotAngles.x) > RotAngleThreshold)
|
||||
Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleX, rotAngles.x)) > RotAngleThreshold)
|
||||
{
|
||||
networkState.RotAngleX = rotAngles.x;
|
||||
networkState.HasRotAngleX = true;
|
||||
@@ -458,7 +470,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
if (SyncRotAngleY &&
|
||||
Mathf.Abs(networkState.RotAngleY - rotAngles.y) > RotAngleThreshold)
|
||||
Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleY, rotAngles.y)) > RotAngleThreshold)
|
||||
{
|
||||
networkState.RotAngleY = rotAngles.y;
|
||||
networkState.HasRotAngleY = true;
|
||||
@@ -466,7 +478,7 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
|
||||
if (SyncRotAngleZ &&
|
||||
Mathf.Abs(networkState.RotAngleZ - rotAngles.z) > RotAngleThreshold)
|
||||
Mathf.Abs(Mathf.DeltaAngle(networkState.RotAngleZ, rotAngles.z)) > RotAngleThreshold)
|
||||
{
|
||||
networkState.RotAngleZ = rotAngles.z;
|
||||
networkState.HasRotAngleZ = true;
|
||||
@@ -509,8 +521,6 @@ namespace Unity.Netcode.Components
|
||||
|
||||
private void ApplyInterpolatedNetworkStateToTransform(NetworkTransformState networkState, Transform transformToUpdate)
|
||||
{
|
||||
m_PrevNetworkState = networkState;
|
||||
|
||||
var interpolatedPosition = InLocalSpace ? transformToUpdate.localPosition : transformToUpdate.position;
|
||||
|
||||
// todo: we should store network state w/ quats vs. euler angles
|
||||
@@ -587,8 +597,6 @@ namespace Unity.Netcode.Components
|
||||
{
|
||||
transformToUpdate.position = interpolatedPosition;
|
||||
}
|
||||
|
||||
m_PrevNetworkState.Position = interpolatedPosition;
|
||||
}
|
||||
|
||||
// RotAngles Apply
|
||||
@@ -602,15 +610,12 @@ namespace Unity.Netcode.Components
|
||||
{
|
||||
transformToUpdate.rotation = Quaternion.Euler(interpolatedRotAngles);
|
||||
}
|
||||
|
||||
m_PrevNetworkState.Rotation = interpolatedRotAngles;
|
||||
}
|
||||
|
||||
// Scale Apply
|
||||
if (SyncScaleX || SyncScaleY || SyncScaleZ)
|
||||
{
|
||||
transformToUpdate.localScale = interpolatedScale;
|
||||
m_PrevNetworkState.Scale = interpolatedScale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,8 +795,6 @@ namespace Unity.Netcode.Components
|
||||
}
|
||||
}
|
||||
|
||||
#region state set
|
||||
|
||||
/// <summary>
|
||||
/// Directly sets a state on the authoritative transform.
|
||||
/// This will override any changes made previously to the transform
|
||||
@@ -851,7 +854,6 @@ namespace Unity.Netcode.Components
|
||||
m_Transform.localScale = scale;
|
||||
m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = shouldTeleport;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// todo this is currently in update, to be able to catch any transform changes. A FixedUpdate mode could be added to be less intense, but it'd be
|
||||
// conditional to users only making transform update changes in FixedUpdate.
|
||||
@@ -879,8 +881,6 @@ namespace Unity.Netcode.Components
|
||||
{
|
||||
TryCommitTransformToServer(m_Transform, m_CachedNetworkManager.LocalTime.Time);
|
||||
}
|
||||
|
||||
m_PrevNetworkState = m_LocalAuthoritativeNetworkState;
|
||||
}
|
||||
|
||||
// apply interpolated value
|
||||
@@ -904,36 +904,10 @@ namespace Unity.Netcode.Components
|
||||
|
||||
if (!CanCommitToTransform)
|
||||
{
|
||||
#if NGO_TRANSFORM_DEBUG
|
||||
if (m_CachedNetworkManager.LogLevel == LogLevel.Developer)
|
||||
{
|
||||
// TODO: This should be a component gizmo - not some debug draw based on log level
|
||||
var interpolatedPosition = new Vector3(m_PositionXInterpolator.GetInterpolatedValue(), m_PositionYInterpolator.GetInterpolatedValue(), m_PositionZInterpolator.GetInterpolatedValue());
|
||||
Debug.DrawLine(interpolatedPosition, interpolatedPosition + Vector3.up, Color.magenta, k_DebugDrawLineTime, false);
|
||||
|
||||
// try to update previously consumed NetworkState
|
||||
// if we have any changes, that means made some updates locally
|
||||
// we apply the latest ReplNetworkState again to revert our changes
|
||||
var oldStateDirtyInfo = ApplyTransformToNetworkStateWithInfo(ref m_PrevNetworkState, 0, m_Transform);
|
||||
|
||||
// there are several bugs in this code, as we the message is dumped out under odd circumstances
|
||||
// For Matt, it would trigger when an object's rotation was perturbed by colliding with another
|
||||
// object vs. explicitly rotating it
|
||||
if (oldStateDirtyInfo.isPositionDirty || oldStateDirtyInfo.isScaleDirty || (oldStateDirtyInfo.isRotationDirty && SyncRotAngleX && SyncRotAngleY && SyncRotAngleZ))
|
||||
{
|
||||
// ignoring rotation dirty since quaternions will mess with euler angles, making this impossible to determine if the change to a single axis comes
|
||||
// from an unauthorized transform change or euler to quaternion conversion artifacts.
|
||||
var dirtyField = oldStateDirtyInfo.isPositionDirty ? "position" : oldStateDirtyInfo.isRotationDirty ? "rotation" : "scale";
|
||||
Debug.LogWarning($"A local change to {dirtyField} without authority detected, reverting back to latest interpolated network state!", this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Apply updated interpolated value
|
||||
ApplyInterpolatedNetworkStateToTransform(m_ReplicatedNetworkState.Value, m_Transform);
|
||||
}
|
||||
}
|
||||
|
||||
m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = false;
|
||||
}
|
||||
|
||||
@@ -960,5 +934,22 @@ namespace Unity.Netcode.Components
|
||||
TryCommitValuesToServer(newPosition, newRotationEuler, newScale, m_CachedNetworkManager.LocalTime.Time);
|
||||
m_LocalAuthoritativeNetworkState.IsTeleportingNextFrame = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this and return false to follow the owner authoritative
|
||||
/// Otherwise, it defaults to server authoritative
|
||||
/// </summary>
|
||||
protected virtual bool OnIsServerAuthoritatitive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by <see cref="NetworkRigidbody"/> to determines if this is server or owner authoritative.
|
||||
/// </summary>
|
||||
internal bool IsServerAuthoritative()
|
||||
{
|
||||
return OnIsServerAuthoritatitive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user