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:
Unity Technologies
2022-04-27 00:00:00 +00:00
parent 60e2dabef4
commit add668dfd2
119 changed files with 4434 additions and 1801 deletions

View File

@@ -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>
/// Theres two factors affecting interpolation: buffering (set in NetworkManagers NetworkTimeSystem) and interpolation time, which is the amount of time itll take to reach the target. This is to affect the second one.
/// </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)
{

View File

@@ -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()
{

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}