1+ using System ;
2+ using UnityEngine ;
3+ using ThreadDispatcher . Core ;
4+
5+ namespace ThreadDispatcher
6+ {
7+ /// <summary>
8+ /// Main dispatcher for marshalling calls to Unity's main thread.
9+ /// </summary>
10+ public class UIThreadDispatcher : MonoBehaviour , IThreadDispatcher
11+ {
12+ private static UIThreadDispatcher _instance ;
13+ private static readonly object _lock = new object ( ) ;
14+
15+ private ActionQueueProcessor _queueProcessor ;
16+ private ThreadChecker _threadChecker ;
17+ private CoroutineRunner _coroutineRunner ;
18+ private ILogger _logger ;
19+
20+ public static UIThreadDispatcher Instance
21+ {
22+ get
23+ {
24+ if ( _instance == null )
25+ {
26+ lock ( _lock )
27+ {
28+ if ( _instance == null )
29+ {
30+ Initialize ( ) ;
31+ }
32+ }
33+ }
34+ return _instance ;
35+ }
36+ }
37+
38+ public static IThreadDispatcher Dispatcher => Instance ;
39+
40+ public bool IsMainThread => _threadChecker ? . IsMainThread ?? true ;
41+ public int QueueSize => _queueProcessor ? . Count ?? 0 ;
42+
43+ [ RuntimeInitializeOnLoadMethod ( RuntimeInitializeLoadType . BeforeSceneLoad ) ]
44+ private static void Initialize ( )
45+ {
46+ if ( _instance != null ) return ;
47+
48+ var go = new GameObject ( "[UIThreadDispatcher]" ) ;
49+ _instance = go . AddComponent < UIThreadDispatcher > ( ) ;
50+ DontDestroyOnLoad ( go ) ;
51+ }
52+
53+ void Awake ( )
54+ {
55+ if ( _instance != null && _instance != this )
56+ {
57+ Destroy ( gameObject ) ;
58+ return ;
59+ }
60+
61+ InitializeComponents ( ) ;
62+ }
63+
64+ private void InitializeComponents ( )
65+ {
66+ _logger = new UnityLogger ( ) ;
67+ _threadChecker = new ThreadChecker ( ) ;
68+ _queueProcessor = new ActionQueueProcessor ( _logger ) ;
69+ _coroutineRunner = gameObject . AddComponent < CoroutineRunner > ( ) ;
70+ }
71+
72+ void Update ( )
73+ {
74+ _queueProcessor ? . ProcessAll ( ) ;
75+ }
76+
77+ public void Enqueue ( Action action )
78+ {
79+ _queueProcessor ? . Enqueue ( action ) ;
80+ }
81+
82+ public void RunOnMainThread ( Action action )
83+ {
84+ if ( action == null )
85+ {
86+ _logger ? . LogWarning ( "Attempted to run null action" ) ;
87+ return ;
88+ }
89+
90+ if ( IsMainThread )
91+ {
92+ action ( ) ;
93+ }
94+ else
95+ {
96+ Enqueue ( action ) ;
97+ }
98+ }
99+
100+ public void EnqueueDelayed ( Action action , float delay )
101+ {
102+ _coroutineRunner ? . RunDelayed ( action , delay ) ;
103+ }
104+
105+ public void EnqueueEndOfFrame ( Action action )
106+ {
107+ _coroutineRunner ? . RunEndOfFrame ( action ) ;
108+ }
109+
110+ public void EnqueueNextFrame ( Action action )
111+ {
112+ _coroutineRunner ? . RunNextFrame ( action ) ;
113+ }
114+
115+ void OnDestroy ( )
116+ {
117+ if ( _instance == this )
118+ {
119+ _queueProcessor ? . Dispose ( ) ;
120+ _instance = null ;
121+ }
122+ }
123+
124+ // Static convenience methods
125+ public static void EnqueueAction ( Action action ) => Instance . Enqueue ( action ) ;
126+ public static void RunOnMain ( Action action ) => Instance . RunOnMainThread ( action ) ;
127+ public static void EnqueueWithDelay ( Action action , float delay ) => Instance . EnqueueDelayed ( action , delay ) ;
128+ public static void EnqueueAtEndOfFrame ( Action action ) => Instance . EnqueueEndOfFrame ( action ) ;
129+ public static void EnqueueForNextFrame ( Action action ) => Instance . EnqueueNextFrame ( action ) ;
130+ }
131+ }
0 commit comments