Skip to content

Instantly share code, notes, and snippets.

@ogxd
Last active March 9, 2020 21:49
Show Gist options
  • Save ogxd/4b2483371f5c652a4a4a6c4b24973dba to your computer and use it in GitHub Desktop.
Save ogxd/4b2483371f5c652a4a4a6c4b24973dba to your computer and use it in GitHub Desktop.
Coroutines outside of Unity's component, global update callback & main thread dispatcher
using System;
using System.Collections.Concurrent;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
[ExecuteInEditMode]
public sealed class MonoContext : MonoBehaviour {
public static UnityEvent OnUpdate;
public static UnityEvent OnApplicationFocused;
// Name of MonoContext GameObject (Unique)
const string NAME = "__MonoContext__";
// Actions remaining to be dispatched in an Unity Thread
private static ConcurrentQueue<Action> actionsToDispatch = new ConcurrentQueue<Action>();
// Reference to unique MonoContext GameObject
private static GameObject monoContextObject;
private static MonoContext instance;
public static MonoContext Instance {
get {
if (instance == null || monoContextObject == null) {
// Takes existing context
GetMonoContextObject();
if (monoContextObject == null) {
// If no context exists, create one.
monoContextObject = new GameObject(NAME);
monoContextObject.hideFlags = HideFlags.HideInHierarchy;
instance = monoContextObject.AddComponent<MonoContext>();
if (Application.isPlaying) DontDestroyOnLoad(monoContextObject);
} else {
instance = monoContextObject.GetComponent<MonoContext>();
if (instance == null)
instance = monoContextObject.AddComponent<MonoContext>();
}
}
return instance;
}
}
public static void GetMonoContextObject() {
foreach (GameObject mcinst in UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().Where(x => x.name == NAME)) {
if (monoContextObject == null) {
monoContextObject = mcinst;
} else {
int ccount = mcinst.GetComponents<MonoContext>().Count();
DestroyImmediate(mcinst);
}
}
}
public static void Clear() {
foreach (GameObject mcinst in UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().Where(x => x.name == NAME)) {
DestroyImmediate(mcinst);
}
monoContextObject = null;
instance = null;
}
public static bool CheckInstance() {
return Instance != null;
}
public static void DispatchInMainThread(Action action) {
if (action != null) {
actionsToDispatch.Enqueue(action);
}
}
public void Update() {
OnUpdate?.Invoke();
Dispatch();
}
private void Dispatch() {
while (actionsToDispatch.Count != 0) {
actionsToDispatch.TryDequeue(out Action action);
if (action != null) {
action.Invoke();
}
}
}
private void OnApplicationFocus(bool focus) {
if (focus) {
OnApplicationFocused?.Invoke();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment