Skip to content

Commit d6723b9

Browse files
test
The test to validate these changes using a DAHost.
1 parent 9d57559 commit d6723b9

File tree

2 files changed

+266
-0
lines changed

2 files changed

+266
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using NUnit.Framework;
5+
using Unity.Netcode.TestHelpers.Runtime;
6+
using UnityEngine;
7+
using UnityEngine.TestTools;
8+
9+
namespace Unity.Netcode.RuntimeTests
10+
{
11+
internal class ParentChildDistibutionTests : IntegrationTestWithApproximation
12+
{
13+
protected override int NumberOfClients => 4;
14+
15+
private GameObject m_GenericPrefab;
16+
private ulong m_OriginalOwnerId;
17+
private List<NetworkObject> m_TargetSpawnedObjects = new List<NetworkObject>();
18+
private List<NetworkObject> m_AltTargetSpawnedObjects = new List<NetworkObject>();
19+
private Dictionary<ulong, List<NetworkObject>> m_AncillarySpawnedObjects = new Dictionary<ulong, List<NetworkObject>>();
20+
private List<NetworkManager> m_NetworkManagers = new List<NetworkManager>();
21+
private StringBuilder m_ErrorMsg = new StringBuilder();
22+
23+
public ParentChildDistibutionTests() : base(HostOrServer.DAHost)
24+
{
25+
}
26+
27+
protected override IEnumerator OnTearDown()
28+
{
29+
m_NetworkManagers.Clear();
30+
m_TargetSpawnedObjects.Clear();
31+
m_AncillarySpawnedObjects.Clear();
32+
m_AltTargetSpawnedObjects.Clear();
33+
return base.OnTearDown();
34+
}
35+
36+
protected override void OnServerAndClientsCreated()
37+
{
38+
m_GenericPrefab = CreateNetworkObjectPrefab("GenPrefab");
39+
var networkObject = m_GenericPrefab.GetComponent<NetworkObject>();
40+
networkObject.DontDestroyWithOwner = true;
41+
base.OnServerAndClientsCreated();
42+
}
43+
44+
private bool AllTargetedInstancesSpawned()
45+
{
46+
m_ErrorMsg.Clear();
47+
foreach (var client in m_NetworkManagers)
48+
{
49+
foreach (var spawnedObject in m_TargetSpawnedObjects)
50+
{
51+
if (!client.SpawnManager.SpawnedObjects.ContainsKey(spawnedObject.NetworkObjectId))
52+
{
53+
m_ErrorMsg.AppendLine($"{client.name} has not spawned {spawnedObject.name}!");
54+
}
55+
}
56+
}
57+
58+
return m_ErrorMsg.Length == 0;
59+
}
60+
61+
private bool AllAncillaryInstancesSpawned()
62+
{
63+
m_ErrorMsg.Clear();
64+
foreach (var client in m_NetworkManagers)
65+
{
66+
foreach (var clientObjects in m_AncillarySpawnedObjects)
67+
{
68+
foreach (var spawnedObject in clientObjects.Value)
69+
{
70+
if (!client.SpawnManager.SpawnedObjects.ContainsKey(spawnedObject.NetworkObjectId))
71+
{
72+
m_ErrorMsg.AppendLine($"{client.name} has not spawned {spawnedObject.name}!");
73+
}
74+
}
75+
}
76+
}
77+
78+
return m_ErrorMsg.Length == 0;
79+
}
80+
81+
/// <summary>
82+
/// Validates that a new owner is assigned to all of the targeted objects
83+
/// </summary>
84+
private bool TargetedObjectsChangedOwnership()
85+
{
86+
m_ErrorMsg.Clear();
87+
var newOwnerId = m_OriginalOwnerId;
88+
foreach (var spawnedObject in m_AltTargetSpawnedObjects)
89+
{
90+
if (spawnedObject.OwnerClientId == m_OriginalOwnerId)
91+
{
92+
m_ErrorMsg.AppendLine($"{spawnedObject.name} still is owned by Client-{m_OriginalOwnerId}!");
93+
}
94+
else if (m_OriginalOwnerId == newOwnerId)
95+
{
96+
newOwnerId = spawnedObject.OwnerClientId;
97+
}
98+
99+
if (spawnedObject.OwnerClientId != newOwnerId)
100+
{
101+
m_ErrorMsg.AppendLine($"{spawnedObject.name} is not owned by Client-{newOwnerId}!");
102+
}
103+
}
104+
return m_ErrorMsg.Length == 0;
105+
}
106+
107+
private bool AncillaryObjectsKeptOwnership()
108+
{
109+
m_ErrorMsg.Clear();
110+
foreach (var clientObjects in m_AncillarySpawnedObjects)
111+
{
112+
foreach (var spawnedObject in clientObjects.Value)
113+
{
114+
if (spawnedObject.OwnerClientId != clientObjects.Key)
115+
{
116+
m_ErrorMsg.AppendLine($"{spawnedObject.name} changed ownership to Client-{spawnedObject.OwnerClientId}!");
117+
}
118+
}
119+
}
120+
return m_ErrorMsg.Length == 0;
121+
}
122+
123+
public enum DistributionTypes
124+
{
125+
UponConnect,
126+
UponDisconnect
127+
}
128+
129+
130+
[UnityTest]
131+
public IEnumerator DistributeOwnerHierarchy([Values] DistributionTypes distributionType)
132+
{
133+
m_NetworkManagers.Clear();
134+
m_TargetSpawnedObjects.Clear();
135+
m_AncillarySpawnedObjects.Clear();
136+
m_AltTargetSpawnedObjects.Clear();
137+
138+
if (distributionType == DistributionTypes.UponConnect)
139+
{
140+
m_ClientNetworkManagers[3].Shutdown();
141+
}
142+
143+
if (!UseCMBService())
144+
{
145+
m_NetworkManagers.Add(m_ServerNetworkManager);
146+
}
147+
m_NetworkManagers.AddRange(m_ClientNetworkManagers);
148+
if (distributionType == DistributionTypes.UponConnect)
149+
{
150+
m_NetworkManagers.Remove(m_ClientNetworkManagers[3]);
151+
}
152+
153+
// When testing connect redistribution,
154+
var instances = distributionType == DistributionTypes.UponDisconnect ? 1 : 2;
155+
var rootObject = (GameObject)null;
156+
var childOne = (GameObject)null;
157+
var childTwo = (GameObject)null;
158+
var networkObject = (NetworkObject)null;
159+
160+
for (int i = 0; i < instances; i++)
161+
{
162+
rootObject = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[0]);
163+
networkObject = rootObject.GetComponent<NetworkObject>();
164+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Distributable);
165+
m_TargetSpawnedObjects.Add(networkObject);
166+
167+
// Used to validate nested transferable transfers to the same owner
168+
childOne = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[0]);
169+
networkObject = childOne.GetComponent<NetworkObject>();
170+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Transferable);
171+
m_TargetSpawnedObjects.Add(networkObject);
172+
173+
// Used to validate nested distributable transfers to the same owner
174+
childTwo = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[0]);
175+
networkObject = childTwo.GetComponent<NetworkObject>();
176+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Distributable);
177+
m_TargetSpawnedObjects.Add(childTwo.GetComponent<NetworkObject>());
178+
179+
childOne.transform.parent = rootObject.transform;
180+
childTwo.transform.parent = rootObject.transform;
181+
}
182+
yield return WaitForConditionOrTimeOut(AllTargetedInstancesSpawned);
183+
AssertOnTimeout($"Timed out waiting for all targeted cloned instances to spawn!\n {m_ErrorMsg}");
184+
185+
// Used to validate that other children do not transfer ownership when redistributing.
186+
187+
var altAchildOne = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[1]);
188+
var altAchildTwo = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[1]);
189+
m_AncillarySpawnedObjects.Add(m_ClientNetworkManagers[1].LocalClientId, new List<NetworkObject>());
190+
networkObject = altAchildOne.GetComponent<NetworkObject>();
191+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Distributable);
192+
m_AncillarySpawnedObjects[m_ClientNetworkManagers[1].LocalClientId].Add(networkObject);
193+
altAchildOne.transform.parent = rootObject.transform;
194+
195+
networkObject = altAchildTwo.GetComponent<NetworkObject>();
196+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Transferable);
197+
m_AncillarySpawnedObjects[m_ClientNetworkManagers[1].LocalClientId].Add(networkObject);
198+
altAchildTwo.transform.parent = rootObject.transform;
199+
200+
var altBchildOne = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[2]);
201+
var altBchildTwo = SpawnObject(m_GenericPrefab, m_ClientNetworkManagers[2]);
202+
m_AncillarySpawnedObjects.Add(m_ClientNetworkManagers[2].LocalClientId, new List<NetworkObject>());
203+
networkObject = altBchildOne.GetComponent<NetworkObject>();
204+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Distributable);
205+
m_AncillarySpawnedObjects[m_ClientNetworkManagers[2].LocalClientId].Add(networkObject);
206+
altBchildOne.transform.parent = rootObject.transform;
207+
208+
networkObject = altBchildTwo.GetComponent<NetworkObject>();
209+
networkObject.SetOwnershipStatus(NetworkObject.OwnershipStatus.Transferable);
210+
m_AncillarySpawnedObjects[m_ClientNetworkManagers[2].LocalClientId].Add(networkObject);
211+
altBchildTwo.transform.parent = rootObject.transform;
212+
213+
yield return WaitForConditionOrTimeOut(AllAncillaryInstancesSpawned);
214+
AssertOnTimeout($"Timed out waiting for all ancillary cloned instances to spawn!\n {m_ErrorMsg}");
215+
216+
// Now disconnect the client that owns the rootObject
217+
// Get the original clientId
218+
m_OriginalOwnerId = m_ClientNetworkManagers[0].LocalClientId;
219+
220+
if (distributionType == DistributionTypes.UponDisconnect)
221+
{
222+
// Swap out the original owner's NetworkObject with one of the other client's since those instances will
223+
// be destroyed when the client disconnects.
224+
foreach (var entry in m_TargetSpawnedObjects)
225+
{
226+
m_AltTargetSpawnedObjects.Add(m_ClientNetworkManagers[1].SpawnManager.SpawnedObjects[entry.NetworkObjectId]);
227+
}
228+
// Disconnect the client to trigger object redistribution
229+
m_ClientNetworkManagers[0].Shutdown();
230+
}
231+
else
232+
{
233+
m_ClientNetworkManagers[3].StartClient();
234+
yield return WaitForConditionOrTimeOut(() => m_ClientNetworkManagers[3].IsConnectedClient);
235+
AssertOnTimeout($"{m_ClientNetworkManagers[3].name} failed to reconnect!");
236+
}
237+
238+
// Verify all of the targeted objects changed ownership to the same client
239+
yield return WaitForConditionOrTimeOut(TargetedObjectsChangedOwnership);
240+
AssertOnTimeout($"All targeted objects did not get distributed to the same owner!\n {m_ErrorMsg}");
241+
242+
// When enabled, you should see one of the two root instances that have children get distributed to
243+
// the reconnected client.
244+
if (m_EnableVerboseDebug && distributionType == DistributionTypes.UponConnect)
245+
{
246+
m_ErrorMsg.Clear();
247+
m_ErrorMsg.AppendLine($"Original targeted objects owner: {m_OriginalOwnerId}");
248+
foreach (var spawnedObject in m_TargetSpawnedObjects)
249+
{
250+
m_ErrorMsg.AppendLine($"{spawnedObject.name} new owner: {spawnedObject.OwnerClientId}");
251+
}
252+
Debug.Log($"{m_ErrorMsg}");
253+
}
254+
255+
// We only want to make sure no other children owned by still connected clients change ownership
256+
if (distributionType == DistributionTypes.UponDisconnect)
257+
{
258+
// Verify the ancillary objects kept the same ownership
259+
yield return WaitForConditionOrTimeOut(AncillaryObjectsKeptOwnership);
260+
AssertOnTimeout($"All ancillary objects did not get distributed to the same owner!\n {m_ErrorMsg}");
261+
}
262+
}
263+
}
264+
}

com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/ParentChildDistibutionTests.cs.meta

Lines changed: 2 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)