Skip to content

Commit 208d1c9

Browse files
fix: RemoveOwnership not locally notifying server that it gained ownership [MTT-6377] [MTT-6937][MTT-6936] (#2618)
* fix This resolves a few ownership related issues specifically noticed when using an owner authoritative NetworkTransform and ownership is removed. This also assures NetworkVariables will be updated if ownership is removed just like they are when ownership is changed. This also fixes an issue where NetworkManager's ShutdownInProgress was not true upon the application quitting which was causing an exception to occur within NetworkVariableBase under specific conditions. * test Removing a warning expect check that is no longer needed. Adding additional checks to validate RemoveOwnership generates an OnOwnershipChanged notification.
1 parent 9af9280 commit 208d1c9

File tree

5 files changed

+46
-58
lines changed

5 files changed

+46
-58
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@ Additional documentation and release notes are available at [Multiplayer Documen
1010

1111
### Added
1212

13-
1413
### Fixed
1514

1615
- Fixed issue where a `NetworkTransform` using full precision state updates was losing transform state updates when interpolation was enabled. (#2624)
1716
- Fixed issue where `NetworkObject.SpawnWithObservers` was not being honored for late joining clients. (#2623)
1817
- Fixed issue where invoking `NetworkManager.Shutdown` multiple times, depending upon the timing, could cause an exception. (#2622)
18+
- Fixed issue where removing ownership would not notify the server that it gained ownership. This also resolves the issue where an owner authoritative NetworkTransform would not properly initialize upon removing ownership from a remote client. (#2618)
1919

20-
## Changed
21-
20+
### Changed
2221

2322
## [1.5.1] - 2023-06-07
2423

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,8 @@ internal void ShutdownInternal()
10351035
// Ensures that the NetworkManager is cleaned up before OnDestroy is run on NetworkObjects and NetworkBehaviours when quitting the application.
10361036
private void OnApplicationQuit()
10371037
{
1038+
// Make sure ShutdownInProgress returns true during this time
1039+
m_ShuttingDown = true;
10381040
OnDestroy();
10391041
}
10401042

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

Lines changed: 12 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,6 @@ internal void UpdateOwnershipTable(NetworkObject networkObject, ulong newOwner,
113113
// Remove the previous owner's entry
114114
OwnershipToObjectsTable[previousOwner].Remove(networkObject.NetworkObjectId);
115115

116-
// Server or Host alway invokes the lost ownership notification locally
117-
if (NetworkManager.IsServer)
118-
{
119-
networkObject.InvokeBehaviourOnLostOwnership();
120-
}
121-
122116
// If we are removing the entry (i.e. despawning or client lost ownership)
123117
if (isRemoving)
124118
{
@@ -143,12 +137,6 @@ internal void UpdateOwnershipTable(NetworkObject networkObject, ulong newOwner,
143137
{
144138
// Add the new ownership entry
145139
OwnershipToObjectsTable[newOwner].Add(networkObject.NetworkObjectId, networkObject);
146-
147-
// Server or Host always invokes the gained ownership notification locally
148-
if (NetworkManager.IsServer)
149-
{
150-
networkObject.InvokeBehaviourOnGainedOwnership();
151-
}
152140
}
153141
else if (isRemoving)
154142
{
@@ -227,43 +215,6 @@ public NetworkObject GetPlayerNetworkObject(ulong clientId)
227215
return null;
228216
}
229217

230-
internal void RemoveOwnership(NetworkObject networkObject)
231-
{
232-
if (!NetworkManager.IsServer)
233-
{
234-
throw new NotServerException("Only the server can change ownership");
235-
}
236-
237-
if (!networkObject.IsSpawned)
238-
{
239-
throw new SpawnStateException("Object is not spawned");
240-
}
241-
242-
// If we made it here then we are the server and if the server is determined to already be the owner
243-
// then ignore the RemoveOwnership invocation.
244-
if (networkObject.OwnerClientId == NetworkManager.ServerClientId)
245-
{
246-
return;
247-
}
248-
249-
networkObject.OwnerClientId = NetworkManager.ServerClientId;
250-
251-
// Server removes the entry and takes over ownership before notifying
252-
UpdateOwnershipTable(networkObject, NetworkManager.ServerClientId, true);
253-
254-
var message = new ChangeOwnershipMessage
255-
{
256-
NetworkObjectId = networkObject.NetworkObjectId,
257-
OwnerClientId = networkObject.OwnerClientId
258-
};
259-
var size = NetworkManager.ConnectionManager.SendMessage(ref message, NetworkDelivery.ReliableSequenced, NetworkManager.ConnectedClientsIds);
260-
261-
foreach (var client in NetworkManager.ConnectedClients)
262-
{
263-
NetworkManager.NetworkMetrics.TrackOwnershipChangeSent(client.Key, networkObject, size);
264-
}
265-
}
266-
267218
/// <summary>
268219
/// Helper function to get a network client for a clientId from the NetworkManager.
269220
/// On the server this will check the <see cref="NetworkManager.ConnectedClients"/> list.
@@ -289,6 +240,11 @@ private bool TryGetNetworkClient(ulong clientId, out NetworkClient networkClient
289240
return false;
290241
}
291242

243+
internal void RemoveOwnership(NetworkObject networkObject)
244+
{
245+
ChangeOwnership(networkObject, NetworkManager.ServerClientId);
246+
}
247+
292248
internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
293249
{
294250
if (!NetworkManager.IsServer)
@@ -301,14 +257,21 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId)
301257
throw new SpawnStateException("Object is not spawned");
302258
}
303259

260+
// Assign the new owner
304261
networkObject.OwnerClientId = clientId;
305262

263+
// Always notify locally on the server when ownership is lost
264+
networkObject.InvokeBehaviourOnLostOwnership();
265+
306266
networkObject.MarkVariablesDirty(true);
307267
NetworkManager.BehaviourUpdater.AddForUpdate(networkObject);
308268

309269
// Server adds entries for all client ownership
310270
UpdateOwnershipTable(networkObject, networkObject.OwnerClientId);
311271

272+
// Always notify locally on the server when a new owner is assigned
273+
networkObject.InvokeBehaviourOnGainedOwnership();
274+
312275
var message = new ChangeOwnershipMessage
313276
{
314277
NetworkObjectId = networkObject.NetworkObjectId,

com.unity.netcode.gameobjects/Tests/Runtime/NetworkBehaviourGenericTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public IEnumerator ValidatedDisableddNetworkBehaviourWarning()
6767
// Set the child object to be inactive in the hierarchy
6868
childObject.SetActive(false);
6969

70-
LogAssert.Expect(LogType.Warning, $"{childObject.name} is disabled! Netcode for GameObjects does not support disabled NetworkBehaviours! The {childBehaviour.GetType().Name} component was skipped during ownership assignment!");
7170
LogAssert.Expect(LogType.Warning, $"{childObject.name} is disabled! Netcode for GameObjects does not support spawning disabled NetworkBehaviours! The {childBehaviour.GetType().Name} component was skipped during spawn!");
7271

7372
parentNetworkObject.Spawn();

com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/NetworkObjectOwnershipTests.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public class NetworkObjectOwnershipTests : NetcodeIntegrationTest
4242

4343
public NetworkObjectOwnershipTests(HostOrServer hostOrServer) : base(hostOrServer) { }
4444

45+
public enum OwnershipChecks
46+
{
47+
Change,
48+
Remove
49+
}
50+
4551
protected override void OnServerAndClientsCreated()
4652
{
4753
m_OwnershipPrefab = CreateNetworkObjectPrefab("OnwershipPrefab");
@@ -62,7 +68,7 @@ public void TestPlayerIsOwned()
6268
}
6369

6470
[UnityTest]
65-
public IEnumerator TestOwnershipCallbacks()
71+
public IEnumerator TestOwnershipCallbacks([Values] OwnershipChecks ownershipChecks)
6672
{
6773
m_OwnershipObject = SpawnObject(m_OwnershipPrefab, m_ServerNetworkManager);
6874
m_OwnershipNetworkObject = m_OwnershipObject.GetComponent<NetworkObject>();
@@ -109,7 +115,17 @@ public IEnumerator TestOwnershipCallbacks()
109115
serverComponent.ResetFlags();
110116
clientComponent.ResetFlags();
111117

112-
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
118+
if (ownershipChecks == OwnershipChecks.Change)
119+
{
120+
// Validates that when ownership is changed back to the server it will get an OnGainedOwnership notification
121+
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
122+
}
123+
else
124+
{
125+
// Validates that when ownership is removed the server gets an OnGainedOwnership notification
126+
serverObject.RemoveOwnership();
127+
}
128+
113129
yield return s_DefaultWaitForTick;
114130

115131
Assert.That(serverComponent.OnGainedOwnershipFired);
@@ -125,7 +141,7 @@ public IEnumerator TestOwnershipCallbacks()
125141
/// Verifies that switching ownership between several clients works properly
126142
/// </summary>
127143
[UnityTest]
128-
public IEnumerator TestOwnershipCallbacksSeveralClients()
144+
public IEnumerator TestOwnershipCallbacksSeveralClients([Values] OwnershipChecks ownershipChecks)
129145
{
130146
// Build our message hook entries tables so we can determine if all clients received spawn or ownership messages
131147
var messageHookEntriesForSpawn = new List<MessageHookEntry>();
@@ -247,8 +263,17 @@ bool WaitForClientsToSpawnNetworkObject()
247263
previousClientComponent = currentClientComponent;
248264
}
249265

250-
// Now change ownership back to the server
251-
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
266+
if (ownershipChecks == OwnershipChecks.Change)
267+
{
268+
// Validates that when ownership is changed back to the server it will get an OnGainedOwnership notification
269+
serverObject.ChangeOwnership(NetworkManager.ServerClientId);
270+
}
271+
else
272+
{
273+
// Validates that when ownership is removed the server gets an OnGainedOwnership notification
274+
serverObject.RemoveOwnership();
275+
}
276+
252277
yield return WaitForConditionOrTimeOut(ownershipMessageHooks);
253278
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out waiting for all clients to receive the {nameof(ChangeOwnershipMessage)} message (back to server).");
254279

0 commit comments

Comments
 (0)