namespace Dreamteck.Splines { using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; #if !UNITY_WSA using System.Threading; #endif public static class SplineThreading { public delegate void EmptyHandler(); public static int threadCount { get { #if UNITY_WSA return 0; #else return threads.Length; #endif } set { #if !UNITY_WSA if(value > threads.Length) { while (threads.Length < value) { ThreadDef thread = new ThreadDef(); #if UNITY_EDITOR if (Application.isPlaying) { thread.Restart(); } #else thread.Restart(); #endif ArrayUtility.Add(ref threads, thread); } } #endif } } #if !UNITY_WSA internal class ThreadDef { internal class Worker { internal bool computing = false; internal Queue instructions = new Queue(); } internal delegate void BoolHandler(bool flag); private ParameterizedThreadStart start = null; internal Thread thread = null; private Worker worker = new Worker(); internal bool isAlive { get { return thread != null && thread.IsAlive; } } internal bool computing { get { return worker.computing; } } internal ThreadDef() { start = new ParameterizedThreadStart(RunThread); } internal void Queue(EmptyHandler handler) { worker.instructions.Enqueue(handler); } internal void Interrupt() { thread.Interrupt(); } internal void Restart() { thread = new Thread(start); thread.Start(worker); } internal void Abort() { if (isAlive) { thread.Abort(); } } } internal static ThreadDef[] threads = new ThreadDef[2]; internal static readonly object locker = new object(); static SplineThreading() { Application.quitting += Quitting; for (int i = 0; i < threads.Length; i++) { threads[i] = new ThreadDef(); } #if UNITY_EDITOR PrewarmThreads(); UnityEditor.EditorApplication.playModeStateChanged += OnPlayStateChanged; #endif } #if UNITY_EDITOR static void OnPlayStateChanged(UnityEditor.PlayModeStateChange state) { if (state == UnityEditor.PlayModeStateChange.ExitingPlayMode) { Quitting(); } } #endif static void Quitting() { Stop(); } static void RunThread(object o) { ThreadDef.Worker work = (ThreadDef.Worker)o; while (true) { try { work.computing = false; Thread.Sleep(Timeout.Infinite); } catch (ThreadInterruptedException) { work.computing = true; lock (locker) { while (work.instructions.Count > 0) { EmptyHandler h = work.instructions.Dequeue(); if (h != null) h(); } } } catch (System.Exception ex) { if(ex.Message != "") Debug.LogError("THREAD EXCEPTION " + ex.Message); break; } } Debug.Log("Thread stopped"); work.computing = false; } #endif public static void Run(EmptyHandler handler) { #if !UNITY_WSA #if UNITY_EDITOR if (!Application.isPlaying) { handler(); return; } #endif for (int i = 0; i < threads.Length; i++) { if (!threads[i].isAlive) threads[i].Restart(); if (!threads[i].computing || i == threads.Length - 1) { threads[i].Queue(handler); if(!threads[i].computing)threads[i].Interrupt(); break; } } #endif } public static void PrewarmThreads() { #if !UNITY_WSA for (int i = 0; i < threads.Length; i++) { if (!threads[i].isAlive) { threads[i].Restart(); } } #endif } public static void Stop() { #if !UNITY_WSA for (int i = 0; i < threads.Length; i++) { threads[i].Abort(); } #endif } } }