@@ -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
0 commit comments