Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Threading;
- using System.Threading.Tasks;
- using UnityEngine;
- public class Timed : Singleton<Timed>
- {
- private static volatile bool paused;
- private static volatile float timeScale = 1f;
- private static volatile int currentFrame;
- private List<EveryFrameCallback> everyFrameCallbacks = new List<EveryFrameCallback>();
- private PooledQueue<EveryFrameCallback> everyFramePool = new PooledQueue<EveryFrameCallback>(() => new EveryFrameCallback());
- private Queue<NextFrameCallback> nextFrameCallbacks = new Queue<NextFrameCallback>();
- private PooledQueue<NextFrameCallback> nextFramePool = new PooledQueue<NextFrameCallback>(() => new NextFrameCallback());
- private ConcurrentQueue<Action> callbacks = new ConcurrentQueue<Action>();
- public static async Task In(float seconds, Action callback, CancellationTokenSource source = null)
- {
- try
- {
- var ins = Ins;
- var delayTask = Task.Delay(TimeSpan.FromSeconds(seconds * timeScale), source?.Token ?? new CancellationToken(false));
- await delayTask.ConfigureAwait(false);
- while (paused)
- {
- Thread.Sleep(1);
- }
- ins.callbacks.Enqueue(callback);
- }
- catch (TaskCanceledException)
- {
- // Ignore
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- public static async Task Every(float seconds, Action callback, int repeatCount = -1, CancellationTokenSource source = null)
- {
- if (seconds <= 0f)
- {
- Debug.LogError("Unable to start Timed task with <= 0f timer!");
- return;
- }
- var ins = Ins;
- try
- {
- while (true)
- {
- var delayTask = Task.Delay(TimeSpan.FromSeconds(seconds * timeScale), source?.Token ?? new CancellationToken(false));
- await delayTask.ConfigureAwait(false);
- while (paused)
- {
- Thread.Sleep(1);
- }
- ins.callbacks.Enqueue(callback);
- if (repeatCount == -1)
- {
- continue;
- }
- if (--repeatCount == 0)
- {
- break;
- }
- }
- }
- catch (TaskCanceledException)
- {
- // Ignore
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- public static EveryFrameStopper EveryFrame(Action callback, int repeatCount = -1)
- {
- var ins = Ins;
- var everyFrameCallback = ins.everyFramePool.Dequeue();
- everyFrameCallback.Setup(callback, repeatCount);
- ins.everyFrameCallbacks.Add(everyFrameCallback);
- return new EveryFrameStopper(everyFrameCallback);
- }
- public static void NextFrame(Action callback)
- {
- var ins = Ins;
- var nextFrameCallback = ins.nextFramePool.Dequeue();
- nextFrameCallback.Setup(callback, currentFrame);
- ins.nextFrameCallbacks.Enqueue(nextFrameCallback);
- }
- private void Update()
- {
- Action callback;
- while (callbacks.TryDequeue(out callback))
- {
- try
- {
- callback?.Invoke();
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- var maxCount = nextFrameCallbacks.Count;
- while (maxCount > 0)
- {
- try
- {
- var nextFrameCallback = nextFrameCallbacks.Dequeue();
- if (nextFrameCallback.Execute(currentFrame))
- {
- nextFramePool.Enqueue(nextFrameCallback);
- }
- else
- {
- nextFrameCallbacks.Enqueue(nextFrameCallback);
- }
- --maxCount;
- }
- catch (Exception e)
- {
- Debug.LogException(e);
- }
- }
- for (var i = everyFrameCallbacks.Count - 1; i >= 0; --i)
- {
- try
- {
- if (!everyFrameCallbacks[i].Execute())
- {
- everyFrameCallbacks.RemoveAt(i);
- }
- }
- catch (Exception e)
- {
- Debug.LogError(e);
- everyFrameCallbacks.RemoveAt(i);
- }
- }
- timeScale = Time.timeScale;
- currentFrame = Time.frameCount;
- }
- private void OnApplicationPause(bool isPaused)
- {
- paused = isPaused;
- }
- private void Awake()
- {
- SetSingletonInstance(this);
- timeScale = Time.timeScale;
- currentFrame = Time.frameCount;
- #if UNITY_EDITOR
- UnityEditor.EditorApplication.playmodeStateChanged += () => { paused = UnityEditor.EditorApplication.isPaused; };
- #endif
- }
- private void Start()
- {
- #if UNITY_EDITOR
- paused = UnityEditor.EditorApplication.isPaused;
- #else
- paused = false;
- #endif
- }
- public class EveryFrameCallback
- {
- public long Revision => revision;
- private long revision;
- private Action Callback { get; set; }
- private int RepeatCount { get; set; }
- private bool cancelled;
- public void Setup(Action callback, int repeatCount = -1)
- {
- Callback = callback;
- RepeatCount = repeatCount;
- cancelled = false;
- Interlocked.Increment(ref revision);
- }
- public bool Execute()
- {
- if (cancelled)
- {
- return false;
- }
- Callback();
- return RepeatCount == -1 || --RepeatCount != 0;
- }
- public void Cancel()
- {
- cancelled = true;
- }
- }
- public struct EveryFrameStopper
- {
- private long capturedRevision;
- private EveryFrameCallback callback;
- public EveryFrameStopper(EveryFrameCallback callback)
- {
- this.callback = callback;
- capturedRevision = callback.Revision;
- }
- public void Cancel()
- {
- if (callback == null || capturedRevision != callback.Revision)
- {
- return;
- }
- capturedRevision = 0;
- callback.Cancel();
- }
- }
- private class NextFrameCallback
- {
- public void Setup(Action action, int capturedFrame)
- {
- Callback = action;
- CapturedFrame = capturedFrame;
- }
- private Action Callback { get; set; }
- private int CapturedFrame { get; set; }
- public bool Execute(int currentFrame)
- {
- if (CapturedFrame == currentFrame)
- {
- return false;
- }
- Callback();
- return true;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement