Skip to content

Commit 706c6b4

Browse files
fix: Provide SpawnWithObservers property alternative to CheckObjectVisibility [MTT-6353] (#2568)
* fix Providing a way for users to specify that a NetworkObject should not spawn with any observers without having to use CheckObjectVisbility as a "global" way to handle this as it conflicts with NetworkShow if the CheckObjectVisbility handler always returns false. * test Test that validates the changes. * update adding changelog entry.
1 parent 347f3c0 commit 706c6b4

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

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

1111
### Added
1212

13+
- Added `NetworkObject.SpawnWithObservers` property (default is true) that when set to false will spawn a `NetworkObject` with no observers and will not be spawned on any client until `NetworkObject.NetworkShow` is invoked. (#2568)
14+
1315
### Fixed
1416

1517
- Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565)

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ internal void GenerateGlobalObjectIdHash()
188188
/// </remarks>
189189
public Action OnMigratedToNewScene;
190190

191+
/// <summary>
192+
/// When set to false, the NetworkObject will be spawned with no observers initially (other than the server)
193+
/// </summary>
194+
[Tooltip("When false, the NetworkObject will spawn with no observers initially. (default is true)")]
195+
public bool SpawnWithObservers = true;
196+
191197
/// <summary>
192198
/// Delegate type for checking visibility
193199
/// </summary>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,10 @@ private void SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
617617
}
618618
}
619619

620-
if (NetworkManager.IsServer)
620+
// If we are the server and should spawn with observers
621+
if (NetworkManager.IsServer && networkObject.SpawnWithObservers)
621622
{
623+
// Add client observers
622624
for (int i = 0; i < NetworkManager.ConnectedClientsList.Count; i++)
623625
{
624626
if (networkObject.CheckObjectVisibility == null || networkObject.CheckObjectVisibility(NetworkManager.ConnectedClientsList[i].ClientId))

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

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,86 @@ public class NetworkObjectOnSpawnTests : NetcodeIntegrationTest
1414

1515
protected override int NumberOfClients => 2;
1616

17+
public enum ObserverTestTypes
18+
{
19+
WithObservers,
20+
WithoutObservers
21+
}
22+
private GameObject m_ObserverPrefab;
23+
private NetworkObject m_ObserverTestNetworkObject;
24+
private ObserverTestTypes m_ObserverTestType;
25+
26+
private const string k_ObserverTestObjName = "ObsObj";
27+
private const string k_WithObserversError = "Not all clients spawned the";
28+
private const string k_WithoutObserversError = "A client spawned the";
29+
30+
protected override void OnServerAndClientsCreated()
31+
{
32+
m_ObserverPrefab = CreateNetworkObjectPrefab(k_ObserverTestObjName);
33+
base.OnServerAndClientsCreated();
34+
}
35+
36+
37+
private bool CheckClientsSideObserverTestObj()
38+
{
39+
foreach (var client in m_ClientNetworkManagers)
40+
{
41+
if (!s_GlobalNetworkObjects.ContainsKey(client.LocalClientId))
42+
{
43+
// When no observers there shouldn't be any client spawned NetworkObjects
44+
// (players are held in a different list)
45+
return !(m_ObserverTestType == ObserverTestTypes.WithObservers);
46+
}
47+
var clientObjects = s_GlobalNetworkObjects[client.LocalClientId];
48+
// Make sure they did spawn the object
49+
if (m_ObserverTestType == ObserverTestTypes.WithObservers)
50+
{
51+
if (!clientObjects.ContainsKey(m_ObserverTestNetworkObject.NetworkObjectId))
52+
{
53+
return false;
54+
}
55+
if (!clientObjects[m_ObserverTestNetworkObject.NetworkObjectId].IsSpawned)
56+
{
57+
return false;
58+
}
59+
}
60+
}
61+
return true;
62+
}
63+
64+
65+
66+
[UnityTest]
67+
public IEnumerator ObserverSpawnTests([Values] ObserverTestTypes observerTestTypes)
68+
{
69+
m_ObserverTestType = observerTestTypes;
70+
var prefabNetworkObject = m_ObserverPrefab.GetComponent<NetworkObject>();
71+
prefabNetworkObject.SpawnWithObservers = observerTestTypes == ObserverTestTypes.WithObservers;
72+
var instance = SpawnObject(m_ObserverPrefab, m_ServerNetworkManager);
73+
m_ObserverTestNetworkObject = instance.GetComponent<NetworkObject>();
74+
var withoutObservers = m_ObserverTestType == ObserverTestTypes.WithoutObservers;
75+
if (withoutObservers)
76+
{
77+
// Just give a little time to make sure nothing spawned
78+
yield return s_DefaultWaitForTick;
79+
}
80+
yield return WaitForConditionOrTimeOut(CheckClientsSideObserverTestObj);
81+
AssertOnTimeout($"{(withoutObservers ? k_WithoutObserversError : k_WithObserversError)} {k_ObserverTestObjName} object!");
82+
// If we spawned without observers
83+
if (withoutObservers)
84+
{
85+
// Make each client an observer
86+
foreach (var client in m_ClientNetworkManagers)
87+
{
88+
m_ObserverTestNetworkObject.NetworkShow(client.LocalClientId);
89+
}
90+
91+
// Validate the clients spawned the NetworkObject
92+
m_ObserverTestType = ObserverTestTypes.WithObservers;
93+
yield return WaitForConditionOrTimeOut(CheckClientsSideObserverTestObj);
94+
AssertOnTimeout($"{k_WithObserversError} {k_ObserverTestObjName} object!");
95+
}
96+
}
1797
/// <summary>
1898
/// Tests that instantiating a <see cref="NetworkObject"/> and destroying without spawning it
1999
/// does not run <see cref="NetworkBehaviour.OnNetworkSpawn"/> or <see cref="NetworkBehaviour.OnNetworkSpawn"/>.
@@ -52,6 +132,11 @@ protected override void OnCreatePlayerPrefab()
52132

53133
protected override IEnumerator OnTearDown()
54134
{
135+
if (m_ObserverPrefab != null)
136+
{
137+
Object.Destroy(m_ObserverPrefab);
138+
}
139+
55140
if (m_TestNetworkObjectPrefab != null)
56141
{
57142
Object.Destroy(m_TestNetworkObjectPrefab);

0 commit comments

Comments
 (0)