123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- using System;
- using System.ComponentModel;
- using System.Linq;
- using System.Threading;
- using BepInEx.Logging;
- using UnityEngine;
- namespace BepInEx
- {
-
-
-
- public sealed class ThreadingHelper : MonoBehaviour, ISynchronizeInvoke
- {
- private readonly object _invokeLock = new object();
- private Action _invokeList;
- private Thread _mainThread;
-
-
-
- public static ThreadingHelper Instance { get; private set; }
-
-
-
-
-
- public static ISynchronizeInvoke SynchronizingObject => Instance;
- internal static void Initialize()
- {
- var go = new GameObject("BepInEx_ThreadingHelper");
- DontDestroyOnLoad(go);
- Instance = go.AddComponent<ThreadingHelper>();
- }
-
-
-
- public void StartSyncInvoke(Action action)
- {
- if (action == null) throw new ArgumentNullException(nameof(action));
- lock (_invokeLock) _invokeList += action;
- }
- private void Update()
- {
-
- if (_mainThread == null)
- _mainThread = Thread.CurrentThread;
-
- if (_invokeList == null) return;
- Action toRun;
- lock (_invokeLock)
- {
- toRun = _invokeList;
- _invokeList = null;
- }
-
-
- foreach (var action in toRun.GetInvocationList().Cast<Action>())
- {
- try
- {
- action();
- }
- catch (Exception ex)
- {
- LogInvocationException(ex);
- }
- }
- }
-
-
-
-
-
-
-
-
- public void StartAsyncInvoke(Func<Action> action)
- {
- void DoWork(object _)
- {
- try
- {
- var result = action();
- if (result != null)
- StartSyncInvoke(result);
- }
- catch (Exception ex)
- {
- LogInvocationException(ex);
- }
- }
- if (!ThreadPool.QueueUserWorkItem(DoWork))
- throw new NotSupportedException("Failed to queue the action on ThreadPool");
- }
- private static void LogInvocationException(Exception ex)
- {
- Logging.Logger.Log(LogLevel.Error, ex);
- if (ex.InnerException != null) Logging.Logger.Log(LogLevel.Error, "INNER: " + ex.InnerException);
- }
- #region ISynchronizeInvoke
- IAsyncResult ISynchronizeInvoke.BeginInvoke(Delegate method, object[] args)
- {
- object Invoke()
- {
- try { return method.DynamicInvoke(args); }
- catch (Exception ex) { return ex; }
- }
- var result = new InvokeResult();
- if (!InvokeRequired)
- result.Finish(Invoke(), true);
- else
- StartSyncInvoke(() => result.Finish(Invoke(), false));
- return result;
- }
- object ISynchronizeInvoke.EndInvoke(IAsyncResult result)
- {
- result.AsyncWaitHandle.WaitOne();
- if (result.AsyncState is Exception ex)
- throw ex;
- return result.AsyncState;
- }
- object ISynchronizeInvoke.Invoke(Delegate method, object[] args)
- {
- var invokeResult = ((ISynchronizeInvoke)this).BeginInvoke(method, args);
- return ((ISynchronizeInvoke)this).EndInvoke(invokeResult);
- }
-
-
-
-
-
- public bool InvokeRequired => _mainThread == null || _mainThread != Thread.CurrentThread;
- private sealed class InvokeResult : IAsyncResult
- {
- public InvokeResult()
- {
- AsyncWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
- }
- public void Finish(object result, bool completedSynchronously)
- {
- AsyncState = result;
- CompletedSynchronously = completedSynchronously;
- IsCompleted = true;
- ((EventWaitHandle)AsyncWaitHandle).Set();
- }
- public bool IsCompleted { get; private set; }
- public WaitHandle AsyncWaitHandle { get; }
- public object AsyncState { get; private set; }
- public bool CompletedSynchronously { get; private set; }
- }
- #endregion
- }
- }
|