Skip to content

Commit 6494b68

Browse files
Merge branch 'develop-2.0.0' into ci/turn-off-single-commit-validation-2.x
2 parents fb4960c + 534f74e commit 6494b68

File tree

8 files changed

+159
-5
lines changed

8 files changed

+159
-5
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
1212

1313
### Fixed
1414

15+
- Fixed `OnClientConnectedCallback` passing incorrect `clientId` when scene management is disabled. (#3312)
16+
- Fixed issue where the `NetworkObject.Ownership` custom editor did not take the default "Everything" flag into consideration. (#3305)
1517
- Fixed DestroyObject flow on non-authority game clients. (#3291)
1618
- Fixed exception being thrown when a `GameObject` with an associated `NetworkTransform` is disabled. (#3243)
1719
- Fixed issue where the scene migration synchronization table was not cleaned up if the `GameObject` of a `NetworkObject` is destroyed before it should have been. (#3230)
@@ -24,6 +26,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2426

2527
### Changed
2628

29+
- Changed root in-scene placed `NetworkObject` instances now will always have either the `Distributable` permission set unless the `SessionOwner` permission is set. (#3305)
2730
- Changed the `DestroyObject` message to reduce the serialized message size and remove the unnecessary message field. (#3304)
2831
- Changed the `NetworkTimeSystem.Sync` method to use half RTT to calculate the desired local time offset as opposed to the full RTT. (#3212)
2932

com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ namespace Unity.Netcode.Editor
1414
[CanEditMultipleObjects]
1515
public class NetworkObjectEditor : UnityEditor.Editor
1616
{
17+
private const NetworkObject.OwnershipStatus k_AllOwnershipFlags = NetworkObject.OwnershipStatus.RequestRequired | NetworkObject.OwnershipStatus.Transferable | NetworkObject.OwnershipStatus.Distributable;
18+
private const int k_SessionOwnerFlagAsInt = (int)NetworkObject.OwnershipStatus.SessionOwner;
19+
1720
private bool m_Initialized;
1821
private NetworkObject m_NetworkObject;
1922
private bool m_ShowObservers;
@@ -114,10 +117,38 @@ public override void OnInspectorGUI()
114117
{
115118
EditorGUI.BeginChangeCheck();
116119
serializedObject.UpdateIfRequiredOrScript();
120+
121+
// Get the current ownership property and precalculate values in order to handle
122+
// the exclusion or inclusion of "all" or just the session owner flags.
123+
var ownershipProperty = serializedObject.FindProperty(nameof(NetworkObject.Ownership));
124+
var previousOwnership = (NetworkObject.OwnershipStatus)ownershipProperty.intValue;
125+
var hadAll = previousOwnership == k_AllOwnershipFlags;
126+
var hadSessionOwner = ownershipProperty.intValue == k_SessionOwnerFlagAsInt;
127+
117128
DrawPropertiesExcluding(serializedObject, k_HiddenFields);
118-
if (m_NetworkObject.IsOwnershipSessionOwner)
129+
130+
// If the ownership flags were changed
131+
var currentOwnership = (NetworkObject.OwnershipStatus)ownershipProperty.intValue;
132+
if (currentOwnership != previousOwnership)
119133
{
120-
m_NetworkObject.Ownership = NetworkObject.OwnershipStatus.SessionOwner;
134+
// Determine if we need to handle setting or removing the session owner flag specifically
135+
// when a user selects the "All" enum flag value.
136+
var hasSessionOwner = currentOwnership.HasFlag(NetworkObject.OwnershipStatus.SessionOwner);
137+
if (hasSessionOwner)
138+
{
139+
if (ownershipProperty.intValue == -1 && !hadAll)
140+
{
141+
ownershipProperty.intValue = (int)k_AllOwnershipFlags;
142+
}
143+
else if ((hadAll && !hadSessionOwner) || (!hadAll && !hadSessionOwner))
144+
{
145+
ownershipProperty.intValue = k_SessionOwnerFlagAsInt;
146+
}
147+
else if (hadSessionOwner && hasSessionOwner)
148+
{
149+
ownershipProperty.intValue &= ~k_SessionOwnerFlagAsInt;
150+
}
151+
}
121152
}
122153
serializedObject.ApplyModifiedProperties();
123154
EditorGUI.EndChangeCheck();

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,15 @@ private void CheckForInScenePlaced()
322322

323323
// Default scene migration synchronization to false for in-scene placed NetworkObjects
324324
SceneMigrationSynchronization = false;
325+
326+
// Root In-scene placed NetworkObjects have to either have the SessionOwner or Distributable permission flag set.
327+
if (transform.parent == null)
328+
{
329+
if (!Ownership.HasFlag(OwnershipStatus.SessionOwner) && !Ownership.HasFlag(OwnershipStatus.Distributable))
330+
{
331+
Ownership |= OwnershipStatus.Distributable;
332+
}
333+
}
325334
}
326335
}
327336
#endif // UNITY_EDITOR
@@ -493,16 +502,36 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
493502
/// <see cref="Transferable"/>: When set, a non-owner can obtain ownership immediately (without requesting and as long as it is not locked).
494503
/// <see cref="RequestRequired"/>: When set, a non-owner must request ownership from the owner (will always get locked once ownership is transferred).
495504
/// <see cref="SessionOwner"/>: When set, only the current session owner may have ownership over this object.
505+
/// <see cref="All"/>: Used within the inspector view only. When selected it will set the Distributable, Transferable, and RequestRequired flags or if those flags are already set it will select the SessionOwner flag by itself.
496506
/// </summary>
497507
// Ranges from 1 to 8 bits
498508
[Flags]
499509
public enum OwnershipStatus
500510
{
511+
/// <summary>
512+
/// When set, this instance will have no permissions (i.e. cannot distribute, transfer, etc).
513+
/// </summary>
501514
None = 0,
515+
/// <summary>
516+
/// When set, this instance will be automatically redistributed when a client joins (if not locked or no request is pending) or leaves.
517+
/// </summary>
502518
Distributable = 1 << 0,
519+
/// <summary>
520+
/// When set, a non-owner can obtain ownership immediately (without requesting and as long as it is not locked).
521+
/// </summary>
503522
Transferable = 1 << 1,
523+
/// <summary>
524+
/// When set, a non-owner must request ownership from the owner (will always get locked once ownership is transferred).
525+
/// </summary>
504526
RequestRequired = 1 << 2,
527+
/// <summary>
528+
/// When set, only the current session owner may have ownership over this object.
529+
/// </summary>
505530
SessionOwner = 1 << 3,
531+
/// <summary>
532+
/// Used within the inspector view only. When selected it will set the Distributable, Transferable, and RequestRequired flags or if those flags are already set it will select the SessionOwner flag by itself.
533+
/// </summary>
534+
All = ~0,
506535
}
507536

508537
/// <summary>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public void Handle(ref NetworkContext context)
305305
NetworkLog.LogInfo($"[Client-{OwnerClientId}][Scene Management Disabled] Synchronization complete!");
306306
}
307307
// When scene management is disabled we notify after everything is synchronized
308-
networkManager.ConnectionManager.InvokeOnClientConnectedCallback(context.SenderId);
308+
networkManager.ConnectionManager.InvokeOnClientConnectedCallback(OwnerClientId);
309309

310310
// For convenience, notify all NetworkBehaviours that synchronization is complete.
311311
networkManager.SpawnManager.NotifyNetworkObjectsSynchronized();

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,9 +1967,12 @@ internal void DistributeNetworkObjects(ulong clientId)
19671967
{
19681968
continue;
19691969
}
1970-
if ((!child.IsOwnershipDistributable || !child.IsOwnershipTransferable) && NetworkManager.LogLevel == LogLevel.Developer)
1970+
if (!child.IsOwnershipDistributable || !child.IsOwnershipTransferable)
19711971
{
1972-
NetworkLog.LogWarning($"Sibling {child.name} of root parent {ownerList.Value[i].name} is neither transferrable or distributable! Object distribution skipped and could lead to a potentially un-owned or owner-mismatched {nameof(NetworkObject)}!");
1972+
if (NetworkManager.LogLevel == LogLevel.Developer)
1973+
{
1974+
NetworkLog.LogWarning($"Sibling {child.name} of root parent {ownerList.Value[i].name} is neither transferrable or distributable! Object distribution skipped and could lead to a potentially un-owned or owner-mismatched {nameof(NetworkObject)}!");
1975+
}
19731976
continue;
19741977
}
19751978
// Transfer ownership of all distributable =or= transferrable children with the same owner to the same client to preserve the sibling ownership tree.

com.unity.netcode.gameobjects/Tests/Runtime/Connection.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using NUnit.Framework;
4+
using Unity.Netcode.TestHelpers.Runtime;
5+
using UnityEngine.TestTools;
6+
7+
namespace Unity.Netcode.RuntimeTests
8+
{
9+
[TestFixture(SceneManagementState.SceneManagementEnabled, NetworkTopologyTypes.DistributedAuthority)]
10+
[TestFixture(SceneManagementState.SceneManagementDisabled, NetworkTopologyTypes.DistributedAuthority)]
11+
[TestFixture(SceneManagementState.SceneManagementEnabled, NetworkTopologyTypes.ClientServer)]
12+
[TestFixture(SceneManagementState.SceneManagementDisabled, NetworkTopologyTypes.ClientServer)]
13+
internal class ClientConnectionTests : IntegrationTestWithApproximation
14+
{
15+
protected override int NumberOfClients => 3;
16+
private readonly bool m_SceneManagementEnabled;
17+
private HashSet<ulong> m_ServerCallbackCalled = new HashSet<ulong>();
18+
private HashSet<ulong> m_ClientCallbackCalled = new HashSet<ulong>();
19+
20+
public ClientConnectionTests(SceneManagementState sceneManagementState, NetworkTopologyTypes networkTopologyType) : base(networkTopologyType)
21+
{
22+
m_SceneManagementEnabled = sceneManagementState == SceneManagementState.SceneManagementEnabled;
23+
}
24+
25+
protected override void OnServerAndClientsCreated()
26+
{
27+
m_ServerNetworkManager.NetworkConfig.EnableSceneManagement = m_SceneManagementEnabled;
28+
m_ServerNetworkManager.OnClientConnectedCallback += Server_OnClientConnectedCallback;
29+
30+
foreach (var client in m_ClientNetworkManagers)
31+
{
32+
client.NetworkConfig.EnableSceneManagement = m_SceneManagementEnabled;
33+
client.OnClientConnectedCallback += Client_OnClientConnectedCallback;
34+
}
35+
36+
base.OnServerAndClientsCreated();
37+
}
38+
39+
[UnityTest]
40+
public IEnumerator VerifyOnClientConnectedCallback()
41+
{
42+
yield return WaitForConditionOrTimeOut(AllCallbacksCalled);
43+
AssertOnTimeout("Timed out waiting for all clients to be connected!");
44+
45+
// The client callbacks should have been called once per client (called once on self)
46+
Assert.True(m_ClientCallbackCalled.Count == NumberOfClients);
47+
48+
// The server callback should be called for self, and then once per client
49+
Assert.True(m_ServerCallbackCalled.Count == 1 + NumberOfClients);
50+
}
51+
52+
private void Server_OnClientConnectedCallback(ulong clientId)
53+
{
54+
if (!m_ServerCallbackCalled.Add(clientId))
55+
{
56+
Assert.Fail($"Client already connected: {clientId}");
57+
}
58+
}
59+
60+
private void Client_OnClientConnectedCallback(ulong clientId)
61+
{
62+
if (!m_ClientCallbackCalled.Add(clientId))
63+
{
64+
Assert.Fail($"Client already connected: {clientId}");
65+
}
66+
}
67+
68+
private bool AllCallbacksCalled()
69+
{
70+
foreach (var client in m_ClientNetworkManagers)
71+
{
72+
if (!m_ClientCallbackCalled.Contains(client.LocalClientId) || !m_ServerCallbackCalled.Contains(client.LocalClientId))
73+
{
74+
return false;
75+
}
76+
}
77+
78+
return m_ServerCallbackCalled.Contains(m_ServerNetworkManager.LocalClientId);
79+
}
80+
}
81+
}
82+

com.unity.netcode.gameobjects/Tests/Runtime/Connection/ClientConnectionTests.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)