-
Notifications
You must be signed in to change notification settings - Fork 294
/
Copy pathDispatcher.cs
112 lines (99 loc) · 3.15 KB
/
Dispatcher.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Threading;
namespace UnityToolbag
{
/// <summary>
/// A system for dispatching code to execute on the main thread.
/// </summary>
[AddComponentMenu("UnityToolbag/Dispatcher")]
public class Dispatcher : MonoBehaviour
{
private static Dispatcher _instance;
// We can't use the behaviour reference from other threads, so we use a separate bool
// to track the instance so we can use that on the other threads.
private static bool _instanceExists;
private static Thread _mainThread;
private static object _lockObject = new object();
private static readonly Queue<Action> _actions = new Queue<Action>();
/// <summary>
/// Gets a value indicating whether or not the current thread is the game's main thread.
/// </summary>
public static bool isMainThread
{
get
{
return Thread.CurrentThread == _mainThread;
}
}
/// <summary>
/// Queues an action to be invoked on the main game thread.
/// </summary>
/// <param name="action">The action to be queued.</param>
public static void InvokeAsync(Action action)
{
if (!_instanceExists) {
Debug.LogError("No Dispatcher exists in the scene. Actions will not be invoked!");
return;
}
if (isMainThread) {
// Don't bother queuing work on the main thread; just execute it.
action();
}
else {
lock (_lockObject) {
_actions.Enqueue(action);
}
}
}
/// <summary>
/// Queues an action to be invoked on the main game thread and blocks the
/// current thread until the action has been executed.
/// </summary>
/// <param name="action">The action to be queued.</param>
public static void Invoke(Action action)
{
if (!_instanceExists) {
Debug.LogError("No Dispatcher exists in the scene. Actions will not be invoked!");
return;
}
bool hasRun = false;
InvokeAsync(() =>
{
action();
hasRun = true;
});
// Lock until the action has run
while (!hasRun) {
Thread.Sleep(5);
}
}
void Awake()
{
if (_instance) {
DestroyImmediate(this);
}
else {
_instance = this;
_instanceExists = true;
_mainThread = Thread.CurrentThread;
}
}
void OnDestroy()
{
if (_instance == this) {
_instance = null;
_instanceExists = false;
}
}
void Update()
{
lock (_lockObject) {
while (_actions.Count > 0) {
_actions.Dequeue()();
}
}
}
}
}