Skip to content

Commit cc3d4e6

Browse files
fix
This fixes the issue where an authority NetworkTransform instance could check for any changes to the transform more than once in a single frame if the frame time was greater than the tick frequency.
1 parent ceb77d7 commit cc3d4e6

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,12 @@ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReade
935935

936936
#region PROPERTIES AND GENERAL METHODS
937937

938+
/// <summary>
939+
/// Used on the authority side only.
940+
/// This is the current network tick and is set within <see cref="NetworkManager.NetworkUpdate(NetworkUpdateStage)"/>.
941+
/// </summary>
942+
internal static int CurrentTick;
943+
938944
/// <summary>
939945
/// Pertains to Owner Authority and Interpolation<br />
940946
/// When enabled (default), 1 additional tick is added to the total number of ticks used to calculate the tick latency ("ticks ago") as a time.
@@ -1878,6 +1884,8 @@ private void TryCommitTransform(ref Transform transformToCommit, bool synchroniz
18781884
// If the state was explicitly set, then update the network tick to match the locally calculate tick
18791885
if (m_LocalAuthoritativeNetworkState.ExplicitSet)
18801886
{
1887+
// For explicit set, we use the current ServerTime.Tick and not CurrentTick since this is a SetState specific flow
1888+
// that is outside of the normal internal tick flow.
18811889
m_LocalAuthoritativeNetworkState.NetworkTick = m_CachedNetworkManager.NetworkTickSystem.ServerTime.Tick;
18821890
}
18831891

@@ -2011,7 +2019,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
20112019
// send a full frame synch.
20122020
var isAxisSync = false;
20132021
// We compare against the NetworkTickSystem version since ServerTime is set when updating ticks
2014-
if (UseUnreliableDeltas && !isSynchronization && m_DeltaSynch && m_NextTickSync <= m_CachedNetworkManager.NetworkTickSystem.ServerTime.Tick)
2022+
if (UseUnreliableDeltas && !isSynchronization && m_DeltaSynch && m_NextTickSync <= CurrentTick)
20152023
{
20162024
// Increment to the next frame synch tick position for this instance
20172025
m_NextTickSync += (int)m_CachedNetworkManager.NetworkConfig.TickRate;
@@ -2179,7 +2187,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
21792187
{
21802188
// If we are teleporting then we can skip the delta threshold check
21812189
isPositionDirty = networkState.IsTeleportingNextFrame || isAxisSync || forceState;
2182-
if (m_HalfFloatTargetTickOwnership > m_CachedNetworkManager.ServerTime.Tick)
2190+
if (m_HalfFloatTargetTickOwnership > CurrentTick)
21832191
{
21842192
isPositionDirty = true;
21852193
}
@@ -2225,7 +2233,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
22252233
networkState.NetworkDeltaPosition = m_HalfPositionState;
22262234

22272235
// If ownership offset is greater or we are doing an axial synchronization then synchronize the base position
2228-
if ((m_HalfFloatTargetTickOwnership > m_CachedNetworkManager.ServerTime.Tick || isAxisSync) && !networkState.IsTeleportingNextFrame)
2236+
if ((m_HalfFloatTargetTickOwnership > CurrentTick || isAxisSync) && !networkState.IsTeleportingNextFrame)
22292237
{
22302238
networkState.SynchronizeBaseHalfFloat = true;
22312239
}
@@ -2409,7 +2417,7 @@ private bool CheckForStateChange(ref NetworkTransformState networkState, ref Tra
24092417
if (enabled)
24102418
{
24112419
// We use the NetworkTickSystem version since ServerTime is set when updating ticks
2412-
networkState.NetworkTick = m_CachedNetworkManager.NetworkTickSystem.ServerTime.Tick;
2420+
networkState.NetworkTick = CurrentTick;
24132421
}
24142422
}
24152423

@@ -2440,7 +2448,7 @@ private void OnNetworkTick(bool isCalledFromParent = false)
24402448
}
24412449

24422450
// If we are nested and have already sent a state update this tick, then exit early (otherwise check for any changes in state)
2443-
if (IsNested && m_LocalAuthoritativeNetworkState.NetworkTick == m_CachedNetworkManager.ServerTime.Tick)
2451+
if (IsNested && m_LocalAuthoritativeNetworkState.NetworkTick == CurrentTick)
24442452
{
24452453
return;
24462454
}
@@ -4500,6 +4508,15 @@ private void UpdateTransformState()
45004508

45014509
#region NETWORK TICK REGISTRATOIN AND HANDLING
45024510
private static Dictionary<NetworkManager, NetworkTransformTickRegistration> s_NetworkTickRegistration = new Dictionary<NetworkManager, NetworkTransformTickRegistration>();
4511+
4512+
internal static void UpdateNetworkTick(NetworkManager networkManager)
4513+
{
4514+
if (s_NetworkTickRegistration.ContainsKey(networkManager))
4515+
{
4516+
s_NetworkTickRegistration[networkManager].TickUpdate();
4517+
}
4518+
}
4519+
45034520
/// <summary>
45044521
/// Adjusts the over-all tick offset (i.e. how many ticks ago) and how wide of a maximum delta time will be used for the
45054522
/// various <see cref="InterpolationTypes"/>.
@@ -4561,9 +4578,8 @@ private static void RemoveTickUpdate(NetworkManager networkManager)
45614578
/// Having the tick update once and cycling through registered instances to update is evidently less processor
45624579
/// intensive than having each instance subscribe and update individually.
45634580
/// </summary>
4564-
private class NetworkTransformTickRegistration
4581+
internal class NetworkTransformTickRegistration
45654582
{
4566-
private Action m_NetworkTickUpdate;
45674583
private NetworkManager m_NetworkManager;
45684584
public HashSet<NetworkTransform> NetworkTransforms = new HashSet<NetworkTransform>();
45694585

@@ -4575,8 +4591,6 @@ private void OnNetworkManagerStopped(bool value)
45754591

45764592
public void Remove()
45774593
{
4578-
m_NetworkManager.NetworkTickSystem.Tick -= m_NetworkTickUpdate;
4579-
m_NetworkTickUpdate = null;
45804594
NetworkTransforms.Clear();
45814595
RemoveTickUpdate(m_NetworkManager);
45824596
}
@@ -4585,10 +4599,10 @@ public void Remove()
45854599
/// Invoked once per network tick, this will update any registered
45864600
/// authority instances.
45874601
/// </summary>
4588-
private void TickUpdate()
4602+
internal void TickUpdate()
45894603
{
45904604
// TODO FIX: The local NetworkTickSystem can invoke with the same network tick as before
4591-
if (m_NetworkManager.ServerTime.Tick <= m_LastTick)
4605+
if (CurrentTick <= m_LastTick)
45924606
{
45934607
return;
45944608
}
@@ -4599,13 +4613,11 @@ private void TickUpdate()
45994613
networkTransform.OnNetworkTick();
46004614
}
46014615
}
4602-
m_LastTick = m_NetworkManager.ServerTime.Tick;
4616+
m_LastTick = CurrentTick;
46034617
}
46044618
public NetworkTransformTickRegistration(NetworkManager networkManager)
46054619
{
46064620
m_NetworkManager = networkManager;
4607-
m_NetworkTickUpdate = new Action(TickUpdate);
4608-
networkManager.NetworkTickSystem.Tick += m_NetworkTickUpdate;
46094621
if (networkManager.IsServer)
46104622
{
46114623
networkManager.OnServerStopped += OnNetworkManagerStopped;

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#endif
1010
using UnityEngine.SceneManagement;
1111
using Debug = UnityEngine.Debug;
12+
using Unity.Netcode.Components;
1213

1314
namespace Unity.Netcode
1415
{
@@ -386,7 +387,19 @@ public void NetworkUpdate(NetworkUpdateStage updateStage)
386387
#endif
387388
case NetworkUpdateStage.PreUpdate:
388389
{
390+
var currentTick = ServerTime.Tick;
389391
NetworkTimeSystem.UpdateTime();
392+
if (ServerTime.Tick != currentTick)
393+
{
394+
// If we have a lower than expected frame rate and our number of ticks that have passed since the last
395+
// frame is greater than 1, then use the first next tick as opposed to the last tick when checking for
396+
// changes in transform state.
397+
// Note: This is an adjustment from using the NetworkTick event as that can be invoked more than once in
398+
// a single frame under the above condition and since any changes to the transform are frame driven there
399+
// is no need to check for changes to the transform more than once per frame.
400+
NetworkTransform.CurrentTick = (ServerTime.Tick - currentTick) > 1 ? currentTick + 1 : ServerTime.Tick;
401+
NetworkTransform.UpdateNetworkTick(this);
402+
}
390403
AnticipationSystem.Update();
391404
}
392405
break;

0 commit comments

Comments
 (0)