123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- using UnityEngine;
- namespace UniRx
- {
- #if UniRxLibrary
- public static partial class SchedulerUnity
- {
- #else
- public static partial class Scheduler
- {
- public static void SetDefaultForUnity()
- {
- Scheduler.DefaultSchedulers.ConstantTimeOperations = Scheduler.Immediate;
- Scheduler.DefaultSchedulers.TailRecursion = Scheduler.Immediate;
- Scheduler.DefaultSchedulers.Iteration = Scheduler.CurrentThread;
- Scheduler.DefaultSchedulers.TimeBasedOperations = MainThread;
- Scheduler.DefaultSchedulers.AsyncConversions = Scheduler.ThreadPool;
- }
- #endif
- static IScheduler mainThread;
- /// <summary>
- /// Unity native MainThread Queue Scheduler. Run on mainthread and delayed on coroutine update loop, elapsed time is calculated based on Time.time.
- /// </summary>
- public static IScheduler MainThread
- {
- get
- {
- return mainThread ?? (mainThread = new MainThreadScheduler());
- }
- }
- static IScheduler mainThreadIgnoreTimeScale;
- /// <summary>
- /// Another MainThread scheduler, delay elapsed time is calculated based on Time.unscaledDeltaTime.
- /// </summary>
- public static IScheduler MainThreadIgnoreTimeScale
- {
- get
- {
- return mainThreadIgnoreTimeScale ?? (mainThreadIgnoreTimeScale = new IgnoreTimeScaleMainThreadScheduler());
- }
- }
- static IScheduler mainThreadFixedUpdate;
- /// <summary>
- /// Run on fixed update mainthread, delay elapsed time is calculated based on Time.fixedTime.
- /// </summary>
- public static IScheduler MainThreadFixedUpdate
- {
- get
- {
- return mainThreadFixedUpdate ?? (mainThreadFixedUpdate = new FixedUpdateMainThreadScheduler());
- }
- }
- static IScheduler mainThreadEndOfFrame;
- /// <summary>
- /// Run on end of frame mainthread, delay elapsed time is calculated based on Time.deltaTime.
- /// </summary>
- public static IScheduler MainThreadEndOfFrame
- {
- get
- {
- return mainThreadEndOfFrame ?? (mainThreadEndOfFrame = new EndOfFrameMainThreadScheduler());
- }
- }
- class MainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing
- {
- readonly Action<object> scheduleAction;
- public MainThreadScheduler()
- {
- MainThreadDispatcher.Initialize();
- scheduleAction = new Action<object>(Schedule);
- }
- // delay action is run in StartCoroutine
- // Okay to action run synchronous and guaranteed run on MainThread
- IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
- {
- // zero == every frame
- if (dueTime == TimeSpan.Zero)
- {
- yield return null; // not immediately, run next frame
- }
- else
- {
- yield return new WaitForSeconds((float)dueTime.TotalSeconds);
- }
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation)
- {
- // zero == every frame
- if (period == TimeSpan.Zero)
- {
- while (true)
- {
- yield return null; // not immediately, run next frame
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- }
- else
- {
- var seconds = (float)(period.TotalMilliseconds / 1000.0);
- var yieldInstruction = new WaitForSeconds(seconds); // cache single instruction object
- while (true)
- {
- yield return yieldInstruction;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- }
- }
- public DateTimeOffset Now
- {
- get { return Scheduler.Now; }
- }
- void Schedule(object state)
- {
- var t = (Tuple<BooleanDisposable, Action>)state;
- if (!t.Item1.IsDisposed)
- {
- t.Item2();
- }
- }
- public IDisposable Schedule(Action action)
- {
- var d = new BooleanDisposable();
- MainThreadDispatcher.Post(scheduleAction, Tuple.Create(d, action));
- return d;
- }
- public IDisposable Schedule(DateTimeOffset dueTime, Action action)
- {
- return Schedule(dueTime - Now, action);
- }
- public IDisposable Schedule(TimeSpan dueTime, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(dueTime);
- MainThreadDispatcher.SendStartCoroutine(DelayAction(time, action, d));
- return d;
- }
- public IDisposable SchedulePeriodic(TimeSpan period, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(period);
- MainThreadDispatcher.SendStartCoroutine(PeriodicAction(time, action, d));
- return d;
- }
- void ScheduleQueueing<T>(object state)
- {
- var t = (Tuple<ICancelable, T, Action<T>>)state;
- if (!t.Item1.IsDisposed)
- {
- t.Item3(t.Item2);
- }
- }
- public void ScheduleQueueing<T>(ICancelable cancel, T state, Action<T> action)
- {
- MainThreadDispatcher.Post(QueuedAction<T>.Instance, Tuple.Create(cancel, state, action));
- }
- static class QueuedAction<T>
- {
- public static readonly Action<object> Instance = new Action<object>(Invoke);
- public static void Invoke(object state)
- {
- var t = (Tuple<ICancelable, T, Action<T>>)state;
- if (!t.Item1.IsDisposed)
- {
- t.Item3(t.Item2);
- }
- }
- }
- }
- class IgnoreTimeScaleMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing
- {
- readonly Action<object> scheduleAction;
- public IgnoreTimeScaleMainThreadScheduler()
- {
- MainThreadDispatcher.Initialize();
- scheduleAction = new Action<object>(Schedule);
- }
- IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
- {
- if (dueTime == TimeSpan.Zero)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- else
- {
- var elapsed = 0f;
- var dt = (float)dueTime.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
- elapsed += Time.unscaledDeltaTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- break;
- }
- }
- }
- }
- IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation)
- {
- // zero == every frame
- if (period == TimeSpan.Zero)
- {
- while (true)
- {
- yield return null; // not immediately, run next frame
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- }
- else
- {
- var elapsed = 0f;
- var dt = (float)period.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
- elapsed += Time.unscaledDeltaTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- elapsed = 0;
- }
- }
- }
- }
- public DateTimeOffset Now
- {
- get { return Scheduler.Now; }
- }
- void Schedule(object state)
- {
- var t = (Tuple<BooleanDisposable, Action>)state;
- if (!t.Item1.IsDisposed)
- {
- t.Item2();
- }
- }
- public IDisposable Schedule(Action action)
- {
- var d = new BooleanDisposable();
- MainThreadDispatcher.Post(scheduleAction, Tuple.Create(d, action));
- return d;
- }
- public IDisposable Schedule(DateTimeOffset dueTime, Action action)
- {
- return Schedule(dueTime - Now, action);
- }
- public IDisposable Schedule(TimeSpan dueTime, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(dueTime);
- MainThreadDispatcher.SendStartCoroutine(DelayAction(time, action, d));
- return d;
- }
- public IDisposable SchedulePeriodic(TimeSpan period, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(period);
- MainThreadDispatcher.SendStartCoroutine(PeriodicAction(time, action, d));
- return d;
- }
- public void ScheduleQueueing<T>(ICancelable cancel, T state, Action<T> action)
- {
- MainThreadDispatcher.Post(QueuedAction<T>.Instance, Tuple.Create(cancel, state, action));
- }
- static class QueuedAction<T>
- {
- public static readonly Action<object> Instance = new Action<object>(Invoke);
- public static void Invoke(object state)
- {
- var t = (Tuple<ICancelable, T, Action<T>>)state;
- if (!t.Item1.IsDisposed)
- {
- t.Item3(t.Item2);
- }
- }
- }
- }
- class FixedUpdateMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing
- {
- public FixedUpdateMainThreadScheduler()
- {
- MainThreadDispatcher.Initialize();
- }
- IEnumerator ImmediateAction<T>(T state, Action<T> action, ICancelable cancellation)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action, state);
- }
- IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
- {
- if (dueTime == TimeSpan.Zero)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- else
- {
- var startTime = Time.fixedTime;
- var dt = (float)dueTime.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
- var elapsed = Time.fixedTime - startTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- break;
- }
- }
- }
- }
- IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation)
- {
- // zero == every frame
- if (period == TimeSpan.Zero)
- {
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- }
- else
- {
- var startTime = Time.fixedTime;
- var dt = (float)period.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
- var ft = Time.fixedTime;
- var elapsed = ft - startTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- startTime = ft;
- }
- }
- }
- }
- public DateTimeOffset Now
- {
- get { return Scheduler.Now; }
- }
- public IDisposable Schedule(Action action)
- {
- return Schedule(TimeSpan.Zero, action);
- }
- public IDisposable Schedule(DateTimeOffset dueTime, Action action)
- {
- return Schedule(dueTime - Now, action);
- }
- public IDisposable Schedule(TimeSpan dueTime, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(dueTime);
- MainThreadDispatcher.StartFixedUpdateMicroCoroutine(DelayAction(time, action, d));
- return d;
- }
- public IDisposable SchedulePeriodic(TimeSpan period, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(period);
- MainThreadDispatcher.StartFixedUpdateMicroCoroutine(PeriodicAction(time, action, d));
- return d;
- }
- public void ScheduleQueueing<T>(ICancelable cancel, T state, Action<T> action)
- {
- MainThreadDispatcher.StartFixedUpdateMicroCoroutine(ImmediateAction(state, action, cancel));
- }
- }
- class EndOfFrameMainThreadScheduler : IScheduler, ISchedulerPeriodic, ISchedulerQueueing
- {
- public EndOfFrameMainThreadScheduler()
- {
- MainThreadDispatcher.Initialize();
- }
- IEnumerator ImmediateAction<T>(T state, Action<T> action, ICancelable cancellation)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action, state);
- }
- IEnumerator DelayAction(TimeSpan dueTime, Action action, ICancelable cancellation)
- {
- if (dueTime == TimeSpan.Zero)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- else
- {
- var elapsed = 0f;
- var dt = (float)dueTime.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
- elapsed += Time.deltaTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- break;
- }
- }
- }
- }
- IEnumerator PeriodicAction(TimeSpan period, Action action, ICancelable cancellation)
- {
- // zero == every frame
- if (period == TimeSpan.Zero)
- {
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) yield break;
- MainThreadDispatcher.UnsafeSend(action);
- }
- }
- else
- {
- var elapsed = 0f;
- var dt = (float)period.TotalSeconds;
- while (true)
- {
- yield return null;
- if (cancellation.IsDisposed) break;
-
- elapsed += Time.deltaTime;
- if (elapsed >= dt)
- {
- MainThreadDispatcher.UnsafeSend(action);
- elapsed = 0;
- }
- }
- }
- }
- public DateTimeOffset Now
- {
- get { return Scheduler.Now; }
- }
- public IDisposable Schedule(Action action)
- {
- return Schedule(TimeSpan.Zero, action);
- }
- public IDisposable Schedule(DateTimeOffset dueTime, Action action)
- {
- return Schedule(dueTime - Now, action);
- }
- public IDisposable Schedule(TimeSpan dueTime, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(dueTime);
- MainThreadDispatcher.StartEndOfFrameMicroCoroutine(DelayAction(time, action, d));
- return d;
- }
- public IDisposable SchedulePeriodic(TimeSpan period, Action action)
- {
- var d = new BooleanDisposable();
- var time = Scheduler.Normalize(period);
- MainThreadDispatcher.StartEndOfFrameMicroCoroutine(PeriodicAction(time, action, d));
- return d;
- }
- public void ScheduleQueueing<T>(ICancelable cancel, T state, Action<T> action)
- {
- MainThreadDispatcher.StartEndOfFrameMicroCoroutine(ImmediateAction(state, action, cancel));
- }
- }
- }
- }
|