1+ using System ;
2+ using System . Linq ;
3+ using System . Collections . Generic ;
4+ using UnityEngine ;
5+ using UnityEngine . LowLevel ;
6+ using UnityEngine . PlayerLoop ;
7+
8+ namespace MLAPI
9+ {
10+ /// <summary>
11+ /// Defines the required interface of a network update system being executed by the network update loop.
12+ /// </summary>
13+ public interface INetworkUpdateSystem
14+ {
15+ void NetworkUpdate ( NetworkUpdateStage updateStage ) ;
16+ }
17+
18+ /// <summary>
19+ /// Defines network update stages being executed by the network update loop.
20+ /// </summary>
21+ public enum NetworkUpdateStage : byte
22+ {
23+ Initialization = 1 ,
24+ EarlyUpdate = 2 ,
25+ FixedUpdate = 3 ,
26+ PreUpdate = 4 ,
27+ Update = 0 , // Default
28+ PreLateUpdate = 5 ,
29+ PostLateUpdate = 6
30+ }
31+
32+ /// <summary>
33+ /// Represents the network update loop injected into low-level player loop in Unity.
34+ /// </summary>
35+ public static class NetworkUpdateLoop
36+ {
37+ private static readonly Dictionary < NetworkUpdateStage , HashSet < INetworkUpdateSystem > > m_UpdateSystem_Sets ;
38+ private static readonly Dictionary < NetworkUpdateStage , INetworkUpdateSystem [ ] > m_UpdateSystem_Arrays ;
39+ private const int k_UpdateSystem_InitialArrayCapacity = 1024 ;
40+
41+ static NetworkUpdateLoop ( )
42+ {
43+ m_UpdateSystem_Sets = new Dictionary < NetworkUpdateStage , HashSet < INetworkUpdateSystem > > ( ) ;
44+ m_UpdateSystem_Arrays = new Dictionary < NetworkUpdateStage , INetworkUpdateSystem [ ] > ( ) ;
45+
46+ foreach ( NetworkUpdateStage updateStage in Enum . GetValues ( typeof ( NetworkUpdateStage ) ) )
47+ {
48+ m_UpdateSystem_Sets . Add ( updateStage , new HashSet < INetworkUpdateSystem > ( ) ) ;
49+ m_UpdateSystem_Arrays . Add ( updateStage , new INetworkUpdateSystem [ k_UpdateSystem_InitialArrayCapacity ] ) ;
50+ }
51+ }
52+
53+ /// <summary>
54+ /// Registers a network update system to be executed in all network update stages.
55+ /// </summary>
56+ public static void RegisterAllNetworkUpdates ( this INetworkUpdateSystem updateSystem )
57+ {
58+ foreach ( NetworkUpdateStage updateStage in Enum . GetValues ( typeof ( NetworkUpdateStage ) ) )
59+ {
60+ RegisterNetworkUpdate ( updateSystem , updateStage ) ;
61+ }
62+ }
63+
64+ /// <summary>
65+ /// Registers a network update system to be executed in a specific network update stage.
66+ /// </summary>
67+ public static void RegisterNetworkUpdate ( this INetworkUpdateSystem updateSystem , NetworkUpdateStage updateStage = NetworkUpdateStage . Update )
68+ {
69+ var sysSet = m_UpdateSystem_Sets [ updateStage ] ;
70+ if ( ! sysSet . Contains ( updateSystem ) )
71+ {
72+ sysSet . Add ( updateSystem ) ;
73+
74+ int setLen = sysSet . Count ;
75+ var sysArr = m_UpdateSystem_Arrays [ updateStage ] ;
76+ int arrLen = sysArr . Length ;
77+
78+ if ( setLen > arrLen )
79+ {
80+ // double capacity
81+ sysArr = m_UpdateSystem_Arrays [ updateStage ] = new INetworkUpdateSystem [ arrLen *= 2 ] ;
82+ }
83+
84+ sysSet . CopyTo ( sysArr ) ;
85+
86+ if ( setLen < arrLen )
87+ {
88+ // null terminator
89+ sysArr [ setLen ] = null ;
90+ }
91+ }
92+ }
93+
94+ /// <summary>
95+ /// Unregisters a network update system from all network update stages.
96+ /// </summary>
97+ public static void UnregisterAllNetworkUpdates ( this INetworkUpdateSystem updateSystem )
98+ {
99+ foreach ( NetworkUpdateStage updateStage in Enum . GetValues ( typeof ( NetworkUpdateStage ) ) )
100+ {
101+ UnregisterNetworkUpdate ( updateSystem , updateStage ) ;
102+ }
103+ }
104+
105+ /// <summary>
106+ /// Unregisters a network update system from a specific network update stage.
107+ /// </summary>
108+ public static void UnregisterNetworkUpdate ( this INetworkUpdateSystem updateSystem , NetworkUpdateStage updateStage = NetworkUpdateStage . Update )
109+ {
110+ var sysSet = m_UpdateSystem_Sets [ updateStage ] ;
111+ if ( sysSet . Contains ( updateSystem ) )
112+ {
113+ sysSet . Remove ( updateSystem ) ;
114+
115+ int setLen = sysSet . Count ;
116+ var sysArr = m_UpdateSystem_Arrays [ updateStage ] ;
117+ int arrLen = sysArr . Length ;
118+
119+ sysSet . CopyTo ( sysArr ) ;
120+
121+ if ( setLen < arrLen )
122+ {
123+ // null terminator
124+ sysArr [ setLen ] = null ;
125+ }
126+ }
127+ }
128+
129+ /// <summary>
130+ /// The current network update stage being executed.
131+ /// </summary>
132+ public static NetworkUpdateStage UpdateStage ;
133+
134+ private static void RunNetworkUpdateStage ( NetworkUpdateStage updateStage )
135+ {
136+ UpdateStage = updateStage ;
137+
138+ var sysArr = m_UpdateSystem_Arrays [ updateStage ] ;
139+ int arrLen = sysArr . Length ;
140+ for ( int curIdx = 0 ; curIdx < arrLen ; curIdx ++ )
141+ {
142+ var curSys = sysArr [ curIdx ] ;
143+ if ( curSys == null )
144+ {
145+ // null terminator
146+ break ;
147+ }
148+
149+ curSys . NetworkUpdate ( updateStage ) ;
150+ }
151+ }
152+
153+ private struct NetworkInitialization
154+ {
155+ public static PlayerLoopSystem CreateLoopSystem ( )
156+ {
157+ return new PlayerLoopSystem
158+ {
159+ type = typeof ( NetworkInitialization ) ,
160+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . Initialization )
161+ } ;
162+ }
163+ }
164+
165+ private struct NetworkEarlyUpdate
166+ {
167+ public static PlayerLoopSystem CreateLoopSystem ( )
168+ {
169+ return new PlayerLoopSystem
170+ {
171+ type = typeof ( NetworkEarlyUpdate ) ,
172+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . EarlyUpdate )
173+ } ;
174+ }
175+ }
176+
177+ private struct NetworkFixedUpdate
178+ {
179+ public static PlayerLoopSystem CreateLoopSystem ( )
180+ {
181+ return new PlayerLoopSystem
182+ {
183+ type = typeof ( NetworkFixedUpdate ) ,
184+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . FixedUpdate )
185+ } ;
186+ }
187+ }
188+
189+ private struct NetworkPreUpdate
190+ {
191+ public static PlayerLoopSystem CreateLoopSystem ( )
192+ {
193+ return new PlayerLoopSystem
194+ {
195+ type = typeof ( NetworkPreUpdate ) ,
196+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . PreUpdate )
197+ } ;
198+ }
199+ }
200+
201+ private struct NetworkUpdate
202+ {
203+ public static PlayerLoopSystem CreateLoopSystem ( )
204+ {
205+ return new PlayerLoopSystem
206+ {
207+ type = typeof ( NetworkUpdate ) ,
208+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . Update )
209+ } ;
210+ }
211+ }
212+
213+ private struct NetworkPreLateUpdate
214+ {
215+ public static PlayerLoopSystem CreateLoopSystem ( )
216+ {
217+ return new PlayerLoopSystem
218+ {
219+ type = typeof ( NetworkPreLateUpdate ) ,
220+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . PreLateUpdate )
221+ } ;
222+ }
223+ }
224+
225+ private struct NetworkPostLateUpdate
226+ {
227+ public static PlayerLoopSystem CreateLoopSystem ( )
228+ {
229+ return new PlayerLoopSystem
230+ {
231+ type = typeof ( NetworkPostLateUpdate ) ,
232+ updateDelegate = ( ) => RunNetworkUpdateStage ( NetworkUpdateStage . PostLateUpdate )
233+ } ;
234+ }
235+ }
236+
237+ [ RuntimeInitializeOnLoadMethod ]
238+ private static void Initialize ( )
239+ {
240+ var customPlayerLoop = PlayerLoop . GetCurrentPlayerLoop ( ) ;
241+
242+ for ( int i = 0 ; i < customPlayerLoop . subSystemList . Length ; i ++ )
243+ {
244+ var playerLoopSystem = customPlayerLoop . subSystemList [ i ] ;
245+
246+ if ( playerLoopSystem . type == typeof ( Initialization ) )
247+ {
248+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
249+ {
250+ // insert at the bottom of `Initialization`
251+ subsystems . Add ( NetworkInitialization . CreateLoopSystem ( ) ) ;
252+ }
253+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
254+ }
255+ else if ( playerLoopSystem . type == typeof ( EarlyUpdate ) )
256+ {
257+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
258+ {
259+ int subsystemCount = subsystems . Count ;
260+ for ( int k = 0 ; k < subsystemCount ; k ++ )
261+ {
262+ if ( subsystems [ k ] . type == typeof ( EarlyUpdate . ScriptRunDelayedStartupFrame ) )
263+ {
264+ // insert before `EarlyUpdate.ScriptRunDelayedStartupFrame`
265+ subsystems . Insert ( k , NetworkEarlyUpdate . CreateLoopSystem ( ) ) ;
266+ break ;
267+ }
268+ }
269+ }
270+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
271+ }
272+ else if ( playerLoopSystem . type == typeof ( FixedUpdate ) )
273+ {
274+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
275+ {
276+ int subsystemCount = subsystems . Count ;
277+ for ( int k = 0 ; k < subsystemCount ; k ++ )
278+ {
279+ if ( subsystems [ k ] . type == typeof ( FixedUpdate . ScriptRunBehaviourFixedUpdate ) )
280+ {
281+ // insert before `FixedUpdate.ScriptRunBehaviourFixedUpdate`
282+ subsystems . Insert ( k , NetworkFixedUpdate . CreateLoopSystem ( ) ) ;
283+ break ;
284+ }
285+ }
286+ }
287+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
288+ }
289+ else if ( playerLoopSystem . type == typeof ( PreUpdate ) )
290+ {
291+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
292+ {
293+ int subsystemCount = subsystems . Count ;
294+ for ( int k = 0 ; k < subsystemCount ; k ++ )
295+ {
296+ if ( subsystems [ k ] . type == typeof ( PreUpdate . PhysicsUpdate ) )
297+ {
298+ // insert before `PreUpdate.PhysicsUpdate`
299+ subsystems . Insert ( k , NetworkPreUpdate . CreateLoopSystem ( ) ) ;
300+ break ;
301+ }
302+ }
303+ }
304+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
305+ }
306+ else if ( playerLoopSystem . type == typeof ( Update ) )
307+ {
308+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
309+ {
310+ int subsystemCount = subsystems . Count ;
311+ for ( int k = 0 ; k < subsystemCount ; k ++ )
312+ {
313+ if ( subsystems [ k ] . type == typeof ( Update . ScriptRunBehaviourUpdate ) )
314+ {
315+ // insert before `Update.ScriptRunBehaviourUpdate`
316+ subsystems . Insert ( k , NetworkUpdate . CreateLoopSystem ( ) ) ;
317+ break ;
318+ }
319+ }
320+ }
321+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
322+ }
323+ else if ( playerLoopSystem . type == typeof ( PreLateUpdate ) )
324+ {
325+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
326+ {
327+ int subsystemCount = subsystems . Count ;
328+ for ( int k = 0 ; k < subsystemCount ; k ++ )
329+ {
330+ if ( subsystems [ k ] . type == typeof ( PreLateUpdate . ScriptRunBehaviourLateUpdate ) )
331+ {
332+ // insert before `PreLateUpdate.ScriptRunBehaviourLateUpdate`
333+ subsystems . Insert ( k , NetworkPreLateUpdate . CreateLoopSystem ( ) ) ;
334+ break ;
335+ }
336+ }
337+ }
338+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
339+ }
340+ else if ( playerLoopSystem . type == typeof ( PostLateUpdate ) )
341+ {
342+ var subsystems = playerLoopSystem . subSystemList . ToList ( ) ;
343+ {
344+ int subsystemCount = subsystems . Count ;
345+ for ( int k = 0 ; k < subsystemCount ; k ++ )
346+ {
347+ if ( subsystems [ k ] . type == typeof ( PostLateUpdate . PlayerSendFrameComplete ) )
348+ {
349+ // insert after `PostLateUpdate.PlayerSendFrameComplete`
350+ subsystems . Insert ( k + 1 , NetworkPostLateUpdate . CreateLoopSystem ( ) ) ;
351+ break ;
352+ }
353+ }
354+ }
355+ playerLoopSystem . subSystemList = subsystems . ToArray ( ) ;
356+ }
357+
358+ customPlayerLoop . subSystemList [ i ] = playerLoopSystem ;
359+ }
360+
361+ PlayerLoop . SetPlayerLoop ( customPlayerLoop ) ;
362+ }
363+ }
364+ }
0 commit comments