Skip to content

Commit 6dd0ae1

Browse files
authored
feat: add WaitForMessageOfType to MultiInstanceHelpers (backport) (#1723)
1 parent a0e4630 commit 6dd0ae1

File tree

2 files changed

+155
-2
lines changed

2 files changed

+155
-2
lines changed

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

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,80 @@ public static class MultiInstanceHelpers
1717
public const int DefaultMinFrames = 1;
1818
public const int DefaultMaxFrames = 64;
1919
private static List<NetworkManager> s_NetworkManagerInstances = new List<NetworkManager>();
20+
private static Dictionary<NetworkManager, MultiInstanceHooks> s_Hooks = new Dictionary<NetworkManager, MultiInstanceHooks>();
2021
private static bool s_IsStarted;
2122
private static int s_ClientCount;
2223
private static int s_OriginalTargetFrameRate = -1;
2324

25+
public delegate bool MessageReceiptCheck(object receivedMessage);
26+
27+
private class MultiInstanceHooks : INetworkHooks
28+
{
29+
public bool IsWaiting;
30+
31+
public MessageReceiptCheck ReceiptCheck;
32+
33+
public static bool CheckForMessageOfType<T>(object receivedMessage) where T : INetworkMessage
34+
{
35+
return receivedMessage is T;
36+
}
37+
38+
39+
public void OnBeforeSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery) where T : INetworkMessage
40+
{
41+
}
42+
43+
public void OnAfterSendMessage<T>(ulong clientId, ref T message, NetworkDelivery delivery, int messageSizeBytes) where T : INetworkMessage
44+
{
45+
}
46+
47+
public void OnBeforeReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
48+
{
49+
}
50+
51+
public void OnAfterReceiveMessage(ulong senderId, Type messageType, int messageSizeBytes)
52+
{
53+
}
54+
55+
public void OnBeforeSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
56+
{
57+
}
58+
59+
public void OnAfterSendBatch(ulong clientId, int messageCount, int batchSizeInBytes, NetworkDelivery delivery)
60+
{
61+
}
62+
63+
public void OnBeforeReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
64+
{
65+
}
66+
67+
public void OnAfterReceiveBatch(ulong senderId, int messageCount, int batchSizeInBytes)
68+
{
69+
}
70+
71+
public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelivery delivery)
72+
{
73+
return true;
74+
}
75+
76+
public bool OnVerifyCanReceive(ulong senderId, Type messageType)
77+
{
78+
return true;
79+
}
80+
81+
public void OnBeforeHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
82+
{
83+
}
84+
85+
public void OnAfterHandleMessage<T>(ref T message, ref NetworkContext context) where T : INetworkMessage
86+
{
87+
if (IsWaiting && (ReceiptCheck == null || ReceiptCheck.Invoke(message)))
88+
{
89+
IsWaiting = false;
90+
}
91+
}
92+
}
93+
2494
private const string k_FirstPartOfTestRunnerSceneName = "InitTestScene";
2595

2696
public static List<NetworkManager> NetworkManagerInstances => s_NetworkManagerInstances;
@@ -175,6 +245,7 @@ public static bool CreateNewClients(int clientCount, out NetworkManager[] client
175245
public static void StopOneClient(NetworkManager clientToStop)
176246
{
177247
clientToStop.Shutdown();
248+
s_Hooks.Remove(clientToStop);
178249
Object.Destroy(clientToStop.gameObject);
179250
NetworkManagerInstances.Remove(clientToStop);
180251
}
@@ -196,6 +267,7 @@ public static void Destroy()
196267
foreach (var networkManager in NetworkManagerInstances)
197268
{
198269
networkManager.Shutdown();
270+
s_Hooks.Remove(networkManager);
199271
}
200272

201273
// Destroy the network manager instances
@@ -292,6 +364,10 @@ public static bool Start(bool host, NetworkManager server, NetworkManager[] clie
292364
server.StartServer();
293365
}
294366

367+
var hooks = new MultiInstanceHooks();
368+
server.MessagingSystem.Hook(hooks);
369+
s_Hooks[server] = hooks;
370+
295371
// if set, then invoke this for the server
296372
RegisterHandlers(server);
297373

@@ -300,6 +376,9 @@ public static bool Start(bool host, NetworkManager server, NetworkManager[] clie
300376
for (int i = 0; i < clients.Length; i++)
301377
{
302378
clients[i].StartClient();
379+
hooks = new MultiInstanceHooks();
380+
clients[i].MessagingSystem.Hook(hooks);
381+
s_Hooks[clients[i]] = hooks;
303382

304383
// if set, then invoke this for the client
305384
RegisterHandlers(clients[i]);
@@ -633,6 +712,74 @@ public static IEnumerator WaitForCondition(Func<bool> predicate, CoroutineResult
633712
Assert.True(res, "PREDICATE CONDITION");
634713
}
635714
}
715+
716+
/// <summary>
717+
/// Waits for a message of the given type to be received
718+
/// </summary>
719+
/// <param name="result">The result. If null, it will fail if the predicate is not met</param>
720+
/// <param name="timeout">The max time in seconds to wait for</param>
721+
internal static IEnumerator WaitForMessageOfType<T>(NetworkManager toBeReceivedBy, CoroutineResultWrapper<bool> result = null, float timeout = 0.5f) where T : INetworkMessage
722+
{
723+
var hooks = s_Hooks[toBeReceivedBy];
724+
hooks.ReceiptCheck = MultiInstanceHooks.CheckForMessageOfType<T>;
725+
if (result == null)
726+
{
727+
result = new CoroutineResultWrapper<bool>();
728+
}
729+
yield return ExecuteWaitForHook(hooks, result, timeout);
730+
731+
Assert.True(result.Result, $"Expected message {typeof(T).Name} was not received within {timeout}s.");
732+
}
733+
734+
/// <summary>
735+
/// Waits for a specific message, defined by a user callback, to be received
736+
/// </summary>
737+
/// <param name="requirement">Called for each received message to check if it's the right one</param>
738+
/// <param name="result">The result. If null, it will fail if the predicate is not met</param>
739+
/// <param name="timeout">The max time in seconds to wait for</param>
740+
internal static IEnumerator WaitForMessageMeetingRequirement(NetworkManager toBeReceivedBy, MessageReceiptCheck requirement, CoroutineResultWrapper<bool> result = null, float timeout = 0.5f)
741+
{
742+
var hooks = s_Hooks[toBeReceivedBy];
743+
hooks.ReceiptCheck = requirement;
744+
if (result == null)
745+
{
746+
result = new CoroutineResultWrapper<bool>();
747+
}
748+
yield return ExecuteWaitForHook(hooks, result, timeout);
749+
750+
Assert.True(result.Result, $"Expected message meeting user requirements was not received within {timeout}s.");
751+
}
752+
753+
private static IEnumerator ExecuteWaitForHook(MultiInstanceHooks hooks, CoroutineResultWrapper<bool> result, float timeout)
754+
{
755+
hooks.IsWaiting = true;
756+
757+
var startTime = Time.realtimeSinceStartup;
758+
759+
while (hooks.IsWaiting && Time.realtimeSinceStartup - startTime < timeout)
760+
{
761+
yield return null;
762+
}
763+
764+
var res = !hooks.IsWaiting;
765+
hooks.IsWaiting = false;
766+
hooks.ReceiptCheck = null;
767+
result.Result = res;
768+
}
769+
770+
public static IEnumerator RunMultiple(IEnumerable<IEnumerator> waitFor)
771+
{
772+
var runningCoroutines = new List<Coroutine>();
773+
foreach (var enumerator in waitFor)
774+
{
775+
runningCoroutines.Add(Run(enumerator));
776+
}
777+
778+
foreach (var coroutine in runningCoroutines)
779+
{
780+
yield return coroutine;
781+
}
782+
}
636783
}
637784

638785
// Empty MonoBehaviour that is a holder of coroutine

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,14 @@ public IEnumerator TestRpcs()
8686
// Send ClientRpc
8787
serverClientPlayerResult.Result.GetComponent<RpcTestNB>().MyClientRpc();
8888

89-
// Wait for RPCs to be received
90-
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForCondition(() => hasReceivedServerRpc && hasReceivedClientRpcLocally && hasReceivedClientRpcRemotely));
89+
var clientMessageResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
90+
var serverMessageResult = new MultiInstanceHelpers.CoroutineResultWrapper<bool>();
91+
// Wait for RPCs to be received - client and server should each receive one.
92+
yield return MultiInstanceHelpers.RunMultiple(new[]
93+
{
94+
MultiInstanceHelpers.WaitForMessageOfType<ClientRpcMessage>(m_ClientNetworkManagers[0], clientMessageResult),
95+
MultiInstanceHelpers.WaitForMessageOfType<ServerRpcMessage>(m_ServerNetworkManager, serverMessageResult),
96+
});
9197

9298
Assert.True(hasReceivedServerRpc, "ServerRpc was not received");
9399
Assert.True(hasReceivedClientRpcLocally, "ClientRpc was not locally received on the server");

0 commit comments

Comments
 (0)