Skip to content

Commit 6493689

Browse files
committed
Fix OnClientBeginSync
1 parent 691750d commit 6493689

File tree

3 files changed

+260
-1
lines changed

3 files changed

+260
-1
lines changed

com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,17 @@ private void OnClientBeginSync(uint sceneEventId)
18791879
sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
18801880

18811881
// Notify local client that a scene load has begun
1882-
InvokeSceneEvents(NetworkManager.LocalClientId, sceneEventData, sceneLoad);
1882+
OnSceneEvent?.Invoke(new SceneEvent()
1883+
{
1884+
AsyncOperation = sceneLoad,
1885+
SceneEventType = SceneEventType.Load,
1886+
LoadSceneMode = loadSceneMode,
1887+
SceneName = sceneName,
1888+
ScenePath = ScenePathFromHash(sceneHash),
1889+
ClientId = NetworkManager.LocalClientId,
1890+
});
1891+
1892+
OnLoad?.Invoke(NetworkManager.LocalClientId, sceneName, loadSceneMode, sceneLoad);
18831893
}
18841894
else
18851895
{
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using NUnit.Framework;
6+
using Unity.Collections;
7+
using Unity.Netcode;
8+
using Unity.Netcode.TestHelpers.Runtime;
9+
using UnityEngine.TestTools;
10+
11+
namespace TestProject.RuntimeTests
12+
{
13+
[TestFixture(HostOrServer.Host)]
14+
[TestFixture(HostOrServer.Server)]
15+
public class SceneManagementSynchronizationTests : NetcodeIntegrationTest
16+
{
17+
protected override int NumberOfClients => 1;
18+
19+
public SceneManagementSynchronizationTests(HostOrServer hostOrServer) : base(hostOrServer)
20+
{
21+
}
22+
23+
private struct ExpectedEvent
24+
{
25+
public SceneEvent SceneEvent;
26+
public ConnectionEventData ConnectionEvent;
27+
}
28+
29+
private readonly Queue<ExpectedEvent> m_ExpectedEventQueue = new();
30+
31+
private static int s_NumEventsProcessed;
32+
33+
private void OnSceneEvent(SceneEvent sceneEvent)
34+
{
35+
VerboseDebug($"OnSceneEvent! Type: {sceneEvent.SceneEventType}.");
36+
AssertEventMatchesExpectedEvent(expectedEvent =>
37+
ValidateSceneEventsAreEqual(expectedEvent, sceneEvent), sceneEvent.SceneEventType);
38+
}
39+
40+
private void OnConnectionEvent(NetworkManager manager, ConnectionEventData eventData)
41+
{
42+
VerboseDebug($"OnConnectionEvent! Type: {eventData.EventType} - Client-{eventData.ClientId}");
43+
AssertEventMatchesExpectedEvent(expectedEvent =>
44+
ValidateConnectionEventsAreEqual(expectedEvent, eventData), eventData.EventType);
45+
}
46+
47+
private void AssertEventMatchesExpectedEvent<T>(Action<ExpectedEvent> predicate, T eventType)
48+
{
49+
if (m_ExpectedEventQueue.Count > 0)
50+
{
51+
var expectedEvent = m_ExpectedEventQueue.Dequeue();
52+
predicate(expectedEvent);
53+
}
54+
else
55+
{
56+
Assert.Fail($"Received unexpected event at index {s_NumEventsProcessed}: {eventType}");
57+
}
58+
59+
s_NumEventsProcessed++;
60+
}
61+
62+
private NetworkManager m_ManagerToTest;
63+
64+
private void SetManagerToTest(NetworkManager manager)
65+
{
66+
m_ManagerToTest = manager;
67+
m_ManagerToTest.OnConnectionEvent += OnConnectionEvent;
68+
m_ManagerToTest.SceneManager.OnSceneEvent += OnSceneEvent;
69+
}
70+
71+
protected override void OnNewClientStarted(NetworkManager networkManager)
72+
{
73+
// If m_ManagerToTest isn't set at this point, it means we are testing the newly created NetworkManager
74+
if (m_ManagerToTest == null)
75+
{
76+
SetManagerToTest(networkManager);
77+
}
78+
base.OnNewClientCreated(networkManager);
79+
}
80+
81+
protected override IEnumerator OnTearDown()
82+
{
83+
m_ManagerToTest.OnConnectionEvent -= OnConnectionEvent;
84+
m_ManagerToTest.SceneManager.OnSceneEvent -= OnSceneEvent;
85+
m_ManagerToTest = null;
86+
m_ExpectedEventQueue.Clear();
87+
s_NumEventsProcessed = 0;
88+
89+
yield return base.OnTearDown();
90+
}
91+
92+
[UnityTest]
93+
public IEnumerator SynchronizationCallbacks_Authority()
94+
{
95+
SetManagerToTest(m_ServerNetworkManager);
96+
97+
// Calculate the expected ID of the newly connecting networkManager
98+
var expectedClientId = m_ClientNetworkManagers[0].LocalClientId + 1;
99+
100+
// Setup expected events
101+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
102+
{
103+
SceneEvent = new SceneEvent()
104+
{
105+
SceneEventType = SceneEventType.Synchronize,
106+
ClientId = expectedClientId
107+
},
108+
});
109+
110+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
111+
{
112+
SceneEvent = new SceneEvent()
113+
{
114+
SceneEventType = SceneEventType.SynchronizeComplete,
115+
ClientId = expectedClientId,
116+
},
117+
});
118+
119+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
120+
{
121+
ConnectionEvent = new ConnectionEventData()
122+
{
123+
EventType = ConnectionEvent.ClientConnected,
124+
ClientId = expectedClientId,
125+
}
126+
});
127+
128+
if (m_UseHost)
129+
{
130+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
131+
{
132+
ConnectionEvent = new ConnectionEventData()
133+
{
134+
EventType = ConnectionEvent.PeerConnected,
135+
ClientId = expectedClientId,
136+
}
137+
});
138+
}
139+
140+
m_EnableVerboseDebug = true;
141+
//////////////////////////////////////////
142+
// Testing event notifications
143+
yield return CreateAndStartNewClient();
144+
yield return s_DefaultWaitForTick;
145+
146+
if (m_ExpectedEventQueue.Count > 0)
147+
{
148+
Assert.Fail($"Failed to invoke all expected callbacks. {m_ExpectedEventQueue.Count} callbacks missing. First missing event is {m_ExpectedEventQueue.Dequeue().SceneEvent.SceneEventType}");
149+
}
150+
}
151+
152+
[UnityTest]
153+
public IEnumerator SynchronizationCallbacks_NonAuthority()
154+
{
155+
var authorityId = m_ServerNetworkManager.LocalClientId;
156+
var peerClientId = m_ClientNetworkManagers[0].LocalClientId;
157+
var expectedClientId = peerClientId + 1;
158+
159+
var expectedPeerClientIds = m_UseHost ? new[] { authorityId, peerClientId } : new[] { peerClientId };
160+
161+
// Setup expected events
162+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
163+
{
164+
ConnectionEvent = new ConnectionEventData()
165+
{
166+
EventType = ConnectionEvent.ClientConnected,
167+
ClientId = expectedClientId,
168+
PeerClientIds = new NativeArray<ulong>(expectedPeerClientIds.ToArray(), Allocator.Persistent),
169+
}
170+
});
171+
172+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
173+
{
174+
SceneEvent = new SceneEvent()
175+
{
176+
SceneEventType = SceneEventType.SynchronizeComplete,
177+
ClientId = expectedClientId,
178+
},
179+
});
180+
181+
Assert.Null(m_ManagerToTest, "m_ManagerToTest should be null as we should be testing newly created client");
182+
183+
//////////////////////////////////////////
184+
// Testing event notifications
185+
186+
// CreateAndStartNewClient will configure m_ManagerToTest inside OnNewClientStarted
187+
yield return CreateAndStartNewClient();
188+
yield return s_DefaultWaitForTick;
189+
190+
Assert.IsEmpty(m_ExpectedEventQueue, "Not all expected callbacks were received");
191+
}
192+
193+
[UnityTest]
194+
public IEnumerator LateJoiningClient_PeerCallbacks()
195+
{
196+
var expectedClientId = m_ClientNetworkManagers[0].LocalClientId + 1;
197+
SetManagerToTest(m_ClientNetworkManagers[0]);
198+
199+
m_ExpectedEventQueue.Enqueue(new ExpectedEvent()
200+
{
201+
ConnectionEvent = new ConnectionEventData()
202+
{
203+
EventType = ConnectionEvent.PeerConnected,
204+
ClientId = expectedClientId,
205+
}
206+
});
207+
208+
//////////////////////////////////////////
209+
// Testing event notifications
210+
yield return CreateAndStartNewClient();
211+
yield return s_DefaultWaitForTick;
212+
213+
Assert.IsEmpty(m_ExpectedEventQueue, "Not all expected callbacks were received");
214+
}
215+
216+
private static void ValidateSceneEventsAreEqual(ExpectedEvent expectedEvent, SceneEvent sceneEvent)
217+
{
218+
Assert.NotNull(expectedEvent.SceneEvent, $"Received unexpected scene event {sceneEvent.SceneEventType} at index {s_NumEventsProcessed}");
219+
AssertField(expectedEvent.SceneEvent.SceneEventType, sceneEvent.SceneEventType, nameof(sceneEvent.SceneEventType), sceneEvent.SceneEventType);
220+
AssertField(expectedEvent.SceneEvent.ClientId, sceneEvent.ClientId, nameof(sceneEvent.ClientId), sceneEvent.SceneEventType);
221+
}
222+
223+
private static void ValidateConnectionEventsAreEqual(ExpectedEvent expectedEvent, ConnectionEventData eventData)
224+
{
225+
Assert.NotNull(expectedEvent.ConnectionEvent, $"Received unexpected connection event {eventData.EventType} at index {s_NumEventsProcessed}");
226+
AssertField(expectedEvent.ConnectionEvent.EventType, eventData.EventType, nameof(eventData.EventType), eventData.EventType);
227+
AssertField(expectedEvent.ConnectionEvent.ClientId, eventData.ClientId, nameof(eventData.ClientId), eventData.EventType);
228+
229+
AssertField(expectedEvent.ConnectionEvent.PeerClientIds.Length, eventData.PeerClientIds.Length, "length of PeerClientIds", eventData.EventType);
230+
if (eventData.PeerClientIds.Length > 0)
231+
{
232+
var peerIds = eventData.PeerClientIds.ToArray();
233+
foreach (var expectedClientId in expectedEvent.ConnectionEvent.PeerClientIds)
234+
{
235+
Assert.Contains(expectedClientId, peerIds, "PeerClientIds does not contain all expected client IDs.");
236+
}
237+
}
238+
}
239+
240+
private static void AssertField<T, TK>(T expected, T actual, string fieldName, TK type)
241+
{
242+
Assert.AreEqual(expected, actual, $"Failed on event {s_NumEventsProcessed} - {type}. Incorrect {fieldName}");
243+
}
244+
245+
}
246+
}

testproject/Assets/Tests/Runtime/NetworkSceneManager/SceneManagementSynchronizationTests.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)