123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
- using System.Threading;
- using System;
- using Cysharp.Threading.Tasks.Internal;
- using UnityEngine;
- namespace Cysharp.Threading.Tasks
- {
- public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem
- {
- readonly CancellationToken cancellationToken;
- readonly Action<object> timerCallback;
- readonly object state;
- readonly PlayerLoopTiming playerLoopTiming;
- readonly bool periodic;
- bool isRunning;
- bool tryStop;
- bool isDisposed;
- protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- {
- this.periodic = periodic;
- this.playerLoopTiming = playerLoopTiming;
- this.cancellationToken = cancellationToken;
- this.timerCallback = timerCallback;
- this.state = state;
- }
- public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- {
- #if UNITY_EDITOR
- // force use Realtime.
- if (PlayerLoopHelper.IsMainThread && !UnityEditor.EditorApplication.isPlaying)
- {
- delayType = DelayType.Realtime;
- }
- #endif
- switch (delayType)
- {
- case DelayType.UnscaledDeltaTime:
- return new IgnoreTimeScalePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
- case DelayType.Realtime:
- return new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
- case DelayType.DeltaTime:
- default:
- return new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state);
- }
- }
- public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- {
- var timer = Create(interval, periodic, delayType, playerLoopTiming, cancellationToken, timerCallback, state);
- timer.Restart();
- return timer;
- }
- /// <summary>
- /// Restart(Reset and Start) timer.
- /// </summary>
- public void Restart()
- {
- if (isDisposed) throw new ObjectDisposedException(null);
- ResetCore(null); // init state
- if (!isRunning)
- {
- isRunning = true;
- PlayerLoopHelper.AddAction(playerLoopTiming, this);
- }
- tryStop = false;
- }
- /// <summary>
- /// Restart(Reset and Start) and change interval.
- /// </summary>
- public void Restart(TimeSpan interval)
- {
- if (isDisposed) throw new ObjectDisposedException(null);
- ResetCore(interval); // init state
- if (!isRunning)
- {
- isRunning = true;
- PlayerLoopHelper.AddAction(playerLoopTiming, this);
- }
- tryStop = false;
- }
- /// <summary>
- /// Stop timer.
- /// </summary>
- public void Stop()
- {
- tryStop = true;
- }
- protected abstract void ResetCore(TimeSpan? newInterval);
- public void Dispose()
- {
- isDisposed = true;
- }
- bool IPlayerLoopItem.MoveNext()
- {
- if (isDisposed)
- {
- isRunning = false;
- return false;
- }
- if (tryStop)
- {
- isRunning = false;
- return false;
- }
- if (cancellationToken.IsCancellationRequested)
- {
- isRunning = false;
- return false;
- }
- if (!MoveNextCore())
- {
- timerCallback(state);
- if (periodic)
- {
- ResetCore(null);
- return true;
- }
- else
- {
- isRunning = false;
- return false;
- }
- }
- return true;
- }
- protected abstract bool MoveNextCore();
- }
- sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer
- {
- int initialFrame;
- float elapsed;
- float interval;
- public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
- {
- ResetCore(interval);
- }
- protected override bool MoveNextCore()
- {
- if (elapsed == 0.0f)
- {
- if (initialFrame == Time.frameCount)
- {
- return true;
- }
- }
- elapsed += Time.deltaTime;
- if (elapsed >= interval)
- {
- return false;
- }
- return true;
- }
- protected override void ResetCore(TimeSpan? interval)
- {
- this.elapsed = 0.0f;
- this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
- if (interval != null)
- {
- this.interval = (float)interval.Value.TotalSeconds;
- }
- }
- }
- sealed class IgnoreTimeScalePlayerLoopTimer : PlayerLoopTimer
- {
- int initialFrame;
- float elapsed;
- float interval;
- public IgnoreTimeScalePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
- {
- ResetCore(interval);
- }
- protected override bool MoveNextCore()
- {
- if (elapsed == 0.0f)
- {
- if (initialFrame == Time.frameCount)
- {
- return true;
- }
- }
- elapsed += Time.unscaledDeltaTime;
- if (elapsed >= interval)
- {
- return false;
- }
- return true;
- }
- protected override void ResetCore(TimeSpan? interval)
- {
- this.elapsed = 0.0f;
- this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
- if (interval != null)
- {
- this.interval = (float)interval.Value.TotalSeconds;
- }
- }
- }
- sealed class RealtimePlayerLoopTimer : PlayerLoopTimer
- {
- ValueStopwatch stopwatch;
- long intervalTicks;
- public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action<object> timerCallback, object state)
- : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state)
- {
- ResetCore(interval);
- }
- protected override bool MoveNextCore()
- {
- if (stopwatch.ElapsedTicks >= intervalTicks)
- {
- return false;
- }
- return true;
- }
- protected override void ResetCore(TimeSpan? interval)
- {
- this.stopwatch = ValueStopwatch.StartNew();
- if (interval != null)
- {
- this.intervalTicks = interval.Value.Ticks;
- }
- }
- }
- }
|