#nullable enable using System; using System.Threading; using ShrinkSDK.Runtime; namespace ShrinkEventBus { public static class ShrinkEventBusRuntime { private static IShrinkMainThreadDispatcher _mainThreadDispatcher = CreateDefaultDispatcher(); public static IShrinkMainThreadDispatcher MainThreadDispatcher => Volatile.Read(ref _mainThreadDispatcher); public static void ConfigureMainThreadDispatcher(IShrinkMainThreadDispatcher dispatcher) { if (dispatcher == null) throw new ArgumentNullException(nameof(dispatcher)); Volatile.Write(ref _mainThreadDispatcher, dispatcher); } private static IShrinkMainThreadDispatcher CreateDefaultDispatcher() { #if UNITY_5_3_OR_NEWER return new ShrinkUnityMainThreadDispatcher(); #else return new ShrinkSynchronizationContextDispatcher( SynchronizationContext.Current, Thread.CurrentThread.ManagedThreadId); #endif } } #if UNITY_5_3_OR_NEWER internal sealed class ShrinkUnityMainThreadDispatcher : IShrinkMainThreadDispatcher { public bool IsMainThread => Cysharp.Threading.Tasks.PlayerLoopHelper.IsMainThread; public bool TryPost(Action action) { if (action == null) throw new ArgumentNullException(nameof(action)); Cysharp.Threading.Tasks.PlayerLoopHelper.AddContinuation( Cysharp.Threading.Tasks.PlayerLoopTiming.Update, action); return true; } } #else internal sealed class ShrinkSynchronizationContextDispatcher : IShrinkMainThreadDispatcher { private readonly SynchronizationContext? _context; private readonly int _threadId; public ShrinkSynchronizationContextDispatcher(SynchronizationContext? context, int threadId) { _context = context; _threadId = threadId; } public bool IsMainThread => Thread.CurrentThread.ManagedThreadId == _threadId; public bool TryPost(Action action) { if (action == null) throw new ArgumentNullException(nameof(action)); if (IsMainThread) { action(); return true; } if (_context == null) return false; _context.Post(static state => ((Action)state!).Invoke(), action); return true; } } #endif }