Skip to content

Commit c1f86c6

Browse files
authored
chore: Optimize NetworkVariable property accessors (#3689)
## Purpose of this PR Optimize property accessors around `NetworkVariable` 1. Keep a self reference to `m_NetworkBehaviour`, `m_NetworkObject` and `m_NetworkManager` 2. Swap `CanWrite` and `CannotWrite` to aggressively inlined functions 3. Store a `m_UseServerTime` boolean that can be calculated once rather than on every check on the NetworkVar 4. Add early returns in the `NetowrkVariableDeltaMessage` to reduce indentation and increase readability. ### Jira ticket Needs a JIRA ticket ### Changelog - Changed: Improved performance of NetworkVariable property accessors. ## Documentation - No documentation changes or additions were necessary. ## Testing & QA (How your changes can be verified during release Playtest) These changes are less risky and should be covered by the automated testing. ### Functional Testing [//]: # (If checked, List manual tests that have been performed.) _Manual testing :_ - [ ] `Manual testing done` _Automated tests:_ - [x] `Covered by existing automated tests` - [ ] `Covered by new automated tests` _Does the change require QA team to:_ - [ ] `Review automated tests`? - [ ] `Execute manual tests`? - [ ] `Provide feedback about the PR`? If any boxes above are checked the QA team will be automatically added as a PR reviewer. ## Backports This is a performance improvement so backporting this fix isn't necessary.
1 parent b78d4eb commit c1f86c6

File tree

6 files changed

+218
-210
lines changed

6 files changed

+218
-210
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1515

1616
### Changed
1717

18+
- Improved performance of the NetworkVariable. (#3683)
1819
- Improved performance around the NetworkBehaviour component. (#3687)
1920

2021
### Deprecated

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs

Lines changed: 167 additions & 170 deletions
Large diffs are not rendered by default.

com.unity.netcode.gameobjects/Runtime/NetworkVariable/AnticipatedNetworkVariable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void Anticipate(T value)
217217
m_LastAnticipationCounter = m_NetworkBehaviour.NetworkManager.AnticipationSystem.AnticipationCounter;
218218
m_AnticipatedValue = value;
219219
NetworkVariableSerialization<T>.Duplicate(m_AnticipatedValue, ref m_PreviousAnticipatedValue);
220-
if (CanWrite)
220+
if (CanWrite())
221221
{
222222
AuthoritativeValue = value;
223223
}

com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ public IEnumerator<T> GetEnumerator()
429429
public void Add(T item)
430430
{
431431
// check write permissions
432-
if (CannotWrite)
432+
if (CannotWrite())
433433
{
434434
LogWritePermissionError();
435435
return;
@@ -456,7 +456,7 @@ public void Add(T item)
456456
public void Clear()
457457
{
458458
// check write permissions
459-
if (CannotWrite)
459+
if (CannotWrite())
460460
{
461461
LogWritePermissionError();
462462
return;
@@ -494,7 +494,7 @@ public bool Contains(T item)
494494
public bool Remove(T item)
495495
{
496496
// check write permissions
497-
if (CannotWrite)
497+
if (CannotWrite())
498498
{
499499
LogWritePermissionError();
500500
return false;
@@ -543,7 +543,7 @@ public int IndexOf(T item)
543543
public void Insert(int index, T item)
544544
{
545545
// check write permissions
546-
if (CannotWrite)
546+
if (CannotWrite())
547547
{
548548
LogWritePermissionError();
549549
return;
@@ -579,7 +579,7 @@ public void Insert(int index, T item)
579579
public void RemoveAt(int index)
580580
{
581581
// check write permissions
582-
if (CannotWrite)
582+
if (CannotWrite())
583583
{
584584
throw new InvalidOperationException("Client is not allowed to write to this NetworkList");
585585
}
@@ -613,7 +613,7 @@ public void RemoveAt(int index)
613613
public void Set(int index, T value, bool forceUpdate = false)
614614
{
615615
// check write permissions
616-
if (CannotWrite)
616+
if (CannotWrite())
617617
{
618618
LogWritePermissionError();
619619
return;

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariable.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public NetworkVariable(T value = default,
8989
/// <param name="value">the value to reset the NetworkVariable to (if none specified it resets to the default)</param>
9090
public void Reset(T value = default)
9191
{
92-
if (m_NetworkBehaviour == null || m_NetworkBehaviour != null && !m_NetworkBehaviour.NetworkObject.IsSpawned)
92+
if (m_NetworkBehaviour == null || m_NetworkObject == null || !m_NetworkObject.IsSpawned)
9393
{
9494
m_InternalValue = value;
9595
NetworkVariableSerialization<T>.Duplicate(m_InternalValue, ref m_LastInternalValue);
@@ -148,7 +148,7 @@ public virtual T Value
148148
get => m_InternalValue;
149149
set
150150
{
151-
if (CannotWrite)
151+
if (CannotWrite())
152152
{
153153
LogWritePermissionError();
154154
return;
@@ -182,7 +182,7 @@ public bool CheckDirtyState(bool forceCheck = false)
182182
var isDirty = base.IsDirty();
183183

184184
// A client without permissions invoking this method should only check to assure the current value is equal to the last known current value
185-
if (CannotWrite)
185+
if (CannotWrite())
186186
{
187187
// If modifications are detected, then revert back to the last known current value
188188
if (!NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_LastInternalValue))
@@ -266,7 +266,7 @@ public override bool IsDirty()
266266
{
267267
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
268268
// to the original collection value prior to applying updates (primarily for collections).
269-
if (!NetworkUpdaterCheck && CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_LastInternalValue))
269+
if (!NetworkUpdaterCheck && CannotWrite() && !NetworkVariableSerialization<T>.AreEqual(ref m_InternalValue, ref m_LastInternalValue))
270270
{
271271
NetworkVariableSerialization<T>.Duplicate(m_LastInternalValue, ref m_InternalValue);
272272
return true;
@@ -328,7 +328,7 @@ public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
328328
{
329329
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
330330
// to the original collection value prior to applying updates (primarily for collections).
331-
if (CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_LastInternalValue, ref m_InternalValue))
331+
if (CannotWrite() && !NetworkVariableSerialization<T>.AreEqual(ref m_LastInternalValue, ref m_InternalValue))
332332
{
333333
NetworkVariableSerialization<T>.Duplicate(m_LastInternalValue, ref m_InternalValue);
334334
}
@@ -370,7 +370,7 @@ public override void ReadField(FastBufferReader reader)
370370
{
371371
// If the client does not have write permissions but the internal value is determined to be locally modified and we are applying updates, then we should revert
372372
// to the original collection value prior to applying updates (primarily for collections).
373-
if (CannotWrite && !NetworkVariableSerialization<T>.AreEqual(ref m_LastInternalValue, ref m_InternalValue))
373+
if (CannotWrite() && !NetworkVariableSerialization<T>.AreEqual(ref m_LastInternalValue, ref m_InternalValue))
374374
{
375375
NetworkVariableSerialization<T>.Duplicate(m_LastInternalValue, ref m_InternalValue);
376376
}

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.CompilerServices;
23
using UnityEngine;
34

45
namespace Unity.Netcode
@@ -42,7 +43,11 @@ public abstract class NetworkVariableBase : IDisposable
4243
/// </summary>
4344
private protected NetworkBehaviour m_NetworkBehaviour;
4445

45-
private NetworkManager m_InternalNetworkManager;
46+
private protected NetworkManager m_NetworkManager;
47+
48+
private protected NetworkObject m_NetworkObject;
49+
50+
private bool m_UseServerTime;
4651

4752
// Determines if this NetworkVariable has been "initialized" to prevent initializing more than once which can happen when first
4853
// instantiated and spawned. If this NetworkVariable instance is on an in-scene placed NetworkObject =or= a pooled NetworkObject
@@ -60,8 +65,6 @@ internal void LogWritePermissionError()
6065
Debug.LogError(GetWritePermissionError());
6166
}
6267

63-
private protected NetworkManager m_NetworkManager => m_InternalNetworkManager;
64-
6568
/// <summary>
6669
/// Gets the NetworkBehaviour instance associated with this network variable
6770
/// </summary>
@@ -108,31 +111,35 @@ public void Initialize(NetworkBehaviour networkBehaviour)
108111
return;
109112
}
110113

111-
if (!m_NetworkBehaviour.NetworkObject.NetworkManagerOwner)
114+
m_NetworkObject = m_NetworkBehaviour.NetworkObject;
115+
116+
if (!m_NetworkObject.NetworkManagerOwner)
112117
{
113118
// Exit early if there has yet to be a NetworkManagerOwner assigned
114119
// to the NetworkObject. This is ok because Initialize is invoked
115120
// multiple times until it is considered "initialized".
116121
return;
117122
}
118-
m_InternalNetworkManager = m_NetworkBehaviour.NetworkObject.NetworkManagerOwner;
123+
m_NetworkManager = m_NetworkObject.NetworkManagerOwner;
124+
125+
m_UseServerTime = m_NetworkManager.CMBServiceConnection || !m_NetworkManager.IsServer;
119126

120127
// When in distributed authority mode, there is no such thing as server write permissions
121-
InternalWritePerm = m_InternalNetworkManager.DistributedAuthorityMode ? NetworkVariableWritePermission.Owner : InternalWritePerm;
128+
InternalWritePerm = m_NetworkManager.DistributedAuthorityMode ? NetworkVariableWritePermission.Owner : InternalWritePerm;
122129

123130
OnInitialize();
124131

125132
// Some unit tests don't operate with a running NetworkManager.
126133
// Only update the last time if there is a NetworkTimeSystem.
127-
if (m_InternalNetworkManager.NetworkTimeSystem != null)
134+
if (m_NetworkManager.NetworkTimeSystem != null)
128135
{
129136
// Update our last sent time relative to when this was initialized
130137
UpdateLastSentTime();
131138

132139
// At this point, this instance is considered initialized
133140
HasBeenInitialized = true;
134141
}
135-
else if (m_InternalNetworkManager.LogLevel == LogLevel.Developer)
142+
else if (m_NetworkManager.LogLevel == LogLevel.Developer)
136143
{
137144
Debug.LogWarning($"[{m_NetworkBehaviour.name}][{m_NetworkBehaviour.GetType().Name}][{GetType().Name}][Initialize] {nameof(NetworkManager)} has no {nameof(NetworkTimeSystem)} assigned!");
138145
}
@@ -251,7 +258,7 @@ public virtual void SetDirty(bool isDirty)
251258
internal bool CanSend()
252259
{
253260
// When connected to a service or not the server, always use the synchronized server time as opposed to the local time
254-
var time = m_InternalNetworkManager.CMBServiceConnection || !m_InternalNetworkManager.IsServer ? m_NetworkBehaviour.NetworkManager.ServerTime.Time : m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime;
261+
var time = m_UseServerTime ? m_NetworkManager.ServerTime.Time : m_NetworkManager.NetworkTimeSystem.LocalTime;
255262
var timeSinceLastUpdate = time - LastUpdateSent;
256263
return
257264
(
@@ -267,7 +274,7 @@ internal bool CanSend()
267274
internal void UpdateLastSentTime()
268275
{
269276
// When connected to a service or not the server, always use the synchronized server time as opposed to the local time
270-
LastUpdateSent = m_InternalNetworkManager.CMBServiceConnection || !m_InternalNetworkManager.IsServer ? m_NetworkBehaviour.NetworkManager.ServerTime.Time : m_NetworkBehaviour.NetworkManager.NetworkTimeSystem.LocalTime;
277+
LastUpdateSent = m_UseServerTime ? m_NetworkManager.ServerTime.Time : m_NetworkManager.NetworkTimeSystem.LocalTime;
271278
}
272279

273280
internal static bool IgnoreInitializeWarning;
@@ -286,27 +293,27 @@ protected void MarkNetworkBehaviourDirty()
286293
}
287294
return;
288295
}
289-
if (m_NetworkBehaviour.NetworkManager.ShutdownInProgress)
296+
if (m_NetworkManager.ShutdownInProgress)
290297
{
291-
if (m_NetworkBehaviour.NetworkManager.LogLevel <= LogLevel.Developer)
298+
if (m_NetworkManager.LogLevel <= LogLevel.Developer)
292299
{
293300
Debug.LogWarning($"NetworkVariable is written to during the NetworkManager shutdown! " +
294301
"Are you modifying a NetworkVariable within a NetworkBehaviour.OnDestroy or NetworkBehaviour.OnDespawn method?");
295302
}
296303
return;
297304
}
298305

299-
if (!m_NetworkBehaviour.NetworkManager.IsListening)
306+
if (!m_NetworkManager.IsListening)
300307
{
301-
if (m_NetworkBehaviour.NetworkManager.LogLevel <= LogLevel.Developer)
308+
if (m_NetworkManager.LogLevel <= LogLevel.Developer)
302309
{
303310
Debug.LogWarning($"NetworkVariable is written to after the NetworkManager has already shutdown! " +
304311
"Are you modifying a NetworkVariable within a NetworkBehaviour.OnDestroy or NetworkBehaviour.OnDespawn method?");
305312
}
306313
return;
307314
}
308315

309-
m_NetworkBehaviour.NetworkManager.BehaviourUpdater?.AddForUpdate(m_NetworkBehaviour.NetworkObject);
316+
m_NetworkManager.BehaviourUpdater?.AddForUpdate(m_NetworkObject);
310317
}
311318

312319
/// <summary>
@@ -345,7 +352,7 @@ public bool CanClientRead(ulong clientId)
345352
}
346353

347354
// When in distributed authority mode, everyone can read (but only the owner can write)
348-
if (m_NetworkManager != null && m_NetworkManager.DistributedAuthorityMode)
355+
if (m_NetworkManager.DistributedAuthorityMode)
349356
{
350357
return true;
351358
}
@@ -355,7 +362,7 @@ public bool CanClientRead(ulong clientId)
355362
case NetworkVariableReadPermission.Everyone:
356363
return true;
357364
case NetworkVariableReadPermission.Owner:
358-
return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId || NetworkManager.ServerClientId == clientId;
365+
return clientId == m_NetworkObject.OwnerClientId || NetworkManager.ServerClientId == clientId;
359366
}
360367
}
361368

@@ -377,26 +384,26 @@ public bool CanClientWrite(ulong clientId)
377384
case NetworkVariableWritePermission.Server:
378385
return clientId == NetworkManager.ServerClientId;
379386
case NetworkVariableWritePermission.Owner:
380-
return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId;
387+
return clientId == m_NetworkObject.OwnerClientId;
381388
}
382389
}
383390

384391
/// <summary>
385392
/// Returns true if the current <see cref="NetworkManager.LocalClientId"/> can write to this variable; otherwise false.
386393
/// </summary>
387-
internal bool CanWrite => m_NetworkManager && CanClientWrite(m_NetworkManager.LocalClientId);
394+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
395+
internal bool CanWrite()
396+
{
397+
return m_NetworkManager && CanClientWrite(m_NetworkManager.LocalClientId);
398+
}
388399

389400
/// <summary>
390401
/// Returns false if the current <see cref="NetworkManager.LocalClientId"/> can write to this variable; otherwise true.
391402
/// </summary>
392-
internal bool CannotWrite => m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId);
393-
394-
/// <summary>
395-
/// Returns the ClientId of the owning client
396-
/// </summary>
397-
internal ulong OwnerClientId()
403+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
404+
internal bool CannotWrite()
398405
{
399-
return m_NetworkBehaviour.NetworkObject.OwnerClientId;
406+
return m_NetworkManager && !CanClientWrite(m_NetworkManager.LocalClientId);
400407
}
401408

402409
/// <summary>
@@ -467,7 +474,10 @@ internal virtual void WriteFieldSynchronization(FastBufferWriter writer)
467474
/// </summary>
468475
public virtual void Dispose()
469476
{
470-
m_InternalNetworkManager = null;
477+
HasBeenInitialized = false;
478+
m_NetworkBehaviour = null;
479+
m_NetworkObject = null;
480+
m_NetworkManager = null;
471481
}
472482
}
473483
}

0 commit comments

Comments
 (0)