Skip to content

Commit de0fd55

Browse files
fix
These changes are the backport fix of #3347.
1 parent 2a4ac2b commit de0fd55

File tree

7 files changed

+71
-16
lines changed

7 files changed

+71
-16
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,14 +1091,23 @@ internal void MarkVariablesDirty(bool dirty)
10911091
}
10921092
}
10931093

1094-
internal void MarkOwnerReadVariablesDirty()
1094+
/// <summary>
1095+
/// For owner read permissions, when changing ownership we need to do a full synchronization
1096+
/// of all NetworkVariables that are owner read permission based since the owner is the only
1097+
/// instance that knows what the most current values are.
1098+
/// </summary>
1099+
internal void MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty()
10951100
{
10961101
for (int j = 0; j < NetworkVariableFields.Count; j++)
10971102
{
10981103
if (NetworkVariableFields[j].ReadPerm == NetworkVariableReadPermission.Owner)
10991104
{
11001105
NetworkVariableFields[j].SetDirty(true);
11011106
}
1107+
if (NetworkVariableFields[j].WritePerm == NetworkVariableWritePermission.Owner)
1108+
{
1109+
NetworkVariableFields[j].OnCheckIsDirtyState();
1110+
}
11021111
}
11031112
}
11041113

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,6 @@ internal void NetworkBehaviourUpdate(bool forceSend = false)
114114
{
115115
behaviour.PostNetworkVariableWrite(forceSend);
116116
}
117-
118-
// Once done processing, we set the previous owner id to the current owner id
119-
dirtyObj.PreviousOwnerId = dirtyObj.OwnerClientId;
120117
}
121118
m_DirtyNetworkObjects.Clear();
122119
}

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,12 +1485,39 @@ internal void MarkVariablesDirty(bool dirty)
14851485
}
14861486
}
14871487

1488-
internal void MarkOwnerReadVariablesDirty()
1488+
/// <summary>
1489+
/// Used when changing ownership, this will mark any owner read permission base NetworkVariables as dirty
1490+
/// and will check if any owner write permission NetworkVariables are dirty (primarily for collections) so
1491+
/// the new owner will get a full state update prior to changing ownership.
1492+
/// </summary>
1493+
/// <remarks>
1494+
/// We have to pass in the original owner and previous owner to "reset" back to the current state of this
1495+
/// NetworkObject in order to preserve the same ownership change flow. By the time this is invoked, the
1496+
/// new and previous owner ids have already been set.
1497+
/// </remarks>
1498+
/// <param name="originalOwnerId">the owner prior to beginning the change in ownership change.</param>
1499+
/// <param name="originalPreviousOwnerId">the previous owner prior to beginning the change in ownership change.</param>
1500+
internal void SynchronizeOwnerNetworkVariables(ulong originalOwnerId, ulong originalPreviousOwnerId)
14891501
{
1502+
var currentOwnerId = OwnerClientId;
1503+
OwnerClientId = originalOwnerId;
1504+
PreviousOwnerId = originalPreviousOwnerId;
14901505
for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
14911506
{
1492-
ChildNetworkBehaviours[i].MarkOwnerReadVariablesDirty();
1507+
ChildNetworkBehaviours[i].MarkOwnerReadDirtyAndCheckOwnerWriteIsDirty();
14931508
}
1509+
1510+
// Now set the new owner and previous owner identifiers back to their original new values
1511+
// before we run the NetworkBehaviourUpdate. For owner read only permissions this order of
1512+
// operations is **particularly important** as we need to first (above) mark things as dirty
1513+
// from the context of the original owner and then second (below) we need to send the messages
1514+
// which requires the new owner to be set for owner read permission NetworkVariables.
1515+
OwnerClientId = currentOwnerId;
1516+
PreviousOwnerId = originalOwnerId;
1517+
1518+
// Force send a state update for all owner read NetworkVariables and any currently dirty
1519+
// owner write NetworkVariables.
1520+
NetworkManager.BehaviourUpdater.NetworkBehaviourUpdate(true);
14941521
}
14951522

14961523
// NGO currently guarantees that the client will receive spawn data for all objects in one network tick.

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,7 @@ public void Handle(ref NetworkContext context)
6262

6363
if (originalOwner == networkManager.LocalClientId)
6464
{
65-
// Mark any owner read variables as dirty
66-
networkObject.MarkOwnerReadVariablesDirty();
67-
// Immediately queue any pending deltas and order the message before the
68-
// change in ownership message.
69-
networkManager.BehaviourUpdater.NetworkBehaviourUpdate(true);
65+
networkObject.SynchronizeOwnerNetworkVariables(originalOwner, networkObject.PreviousOwnerId);
7066
}
7167

7268
networkObject.InvokeOwnershipChanged(originalOwner, OwnerClientId);

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ public bool CheckDirtyState(bool forceCheck = false)
166166
return isDirty;
167167
}
168168

169+
/// <inheritdoc/>
170+
internal override void OnCheckIsDirtyState()
171+
{
172+
CheckDirtyState();
173+
base.OnCheckIsDirtyState();
174+
}
175+
169176
internal ref T RefValue()
170177
{
171178
return ref m_InternalValue;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,15 @@ internal ulong OwnerClientId()
345345
return m_NetworkBehaviour.NetworkObject.OwnerClientId;
346346
}
347347

348+
/// <summary>
349+
/// Primarily to check for collections dirty states when doing
350+
/// a fully owner read/write NetworkVariable update.
351+
/// </summary>
352+
internal virtual void OnCheckIsDirtyState()
353+
{
354+
355+
}
356+
348357
/// <summary>
349358
/// Writes the dirty changes, that is, the changes since the variable was last dirty, to the writer
350359
/// </summary>

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,17 @@ internal void RemoveOwnership(NetworkObject networkObject)
250250

251251
internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
252252
{
253+
254+
if (clientId == networkObject.OwnerClientId)
255+
{
256+
if (NetworkManager.LogLevel <= LogLevel.Developer)
257+
{
258+
Debug.LogWarning($"[{nameof(NetworkSpawnManager)}][{nameof(ChangeOwnership)}] Attempting to change ownership to Client-{clientId} when the owner is already {networkObject.OwnerClientId}! (Ignoring)");
259+
260+
}
261+
return;
262+
}
263+
253264
// If ownership changes faster than the latency between the client-server and there are NetworkVariables being updated during ownership changes,
254265
// then notify the user they could potentially lose state updates if developer logging is enabled.
255266
if (m_LastChangeInOwnership.ContainsKey(networkObject.NetworkObjectId) && m_LastChangeInOwnership[networkObject.NetworkObjectId] > Time.realtimeSinceStartup)
@@ -278,6 +289,8 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
278289
{
279290
throw new SpawnStateException("Object is not spawned");
280291
}
292+
var originalPreviousOwnerId = networkObject.PreviousOwnerId;
293+
var originalOwner = networkObject.OwnerClientId;
281294

282295
// Used to distinguish whether a new owner should receive any currently dirty NetworkVariable updates
283296
networkObject.PreviousOwnerId = networkObject.OwnerClientId;
@@ -294,13 +307,10 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
294307
// Always notify locally on the server when a new owner is assigned
295308
networkObject.InvokeBehaviourOnGainedOwnership();
296309

310+
// If we are the original owner, then we want to synchronize owner read & write NetworkVariables.
297311
if (networkObject.PreviousOwnerId == NetworkManager.LocalClientId)
298312
{
299-
// Mark any owner read variables as dirty
300-
networkObject.MarkOwnerReadVariablesDirty();
301-
// Immediately queue any pending deltas and order the message before the
302-
// change in ownership message.
303-
NetworkManager.BehaviourUpdater.NetworkBehaviourUpdate(true);
313+
networkObject.SynchronizeOwnerNetworkVariables(originalOwner, originalPreviousOwnerId);
304314
}
305315

306316
var message = new ChangeOwnershipMessage

0 commit comments

Comments
 (0)