Add ultimate xr
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7319f4707f694720bbc7b2520eff6493
|
||||
timeCreated: 1644230689
|
||||
@@ -0,0 +1,207 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrCancellableController.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UltimateXR.Extensions.System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Threading.TaskControllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Parent abstract class that simplifies running a job which can be canceled through a
|
||||
/// <see cref="CancellationToken" />.<br />
|
||||
/// It wraps a <see cref="CancellationTokenSource" /> into a <see cref="Start()" /> and <see cref="Stop" /> pattern,
|
||||
/// ensuring that the
|
||||
/// <see cref="Stop" /> is called if the application quits abruptly or the Unity editor exits playmode.
|
||||
/// </summary>
|
||||
/// <seealso cref="UxrTaskController" />
|
||||
/// <seealso cref="UxrLoopController" />
|
||||
public abstract class UxrCancellableController
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the inner job is completed, without having been canceled.
|
||||
/// </summary>
|
||||
public event EventHandler Completed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the inner job is currently running.
|
||||
/// </summary>
|
||||
public bool IsRunning => _cts != null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
protected UxrCancellableController()
|
||||
{
|
||||
Application.quitting += Application_quitting;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Starts running the inner job until completion or <see cref="Stop" /> is called.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
Start(0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts using an initial <paramref name="delayMilliseconds" />.
|
||||
/// </summary>
|
||||
/// <param name="delayMilliseconds">
|
||||
/// Delay in milliseconds before <see cref="Start()" /> is automatically called.
|
||||
/// </param>
|
||||
public void StartAfterMilliseconds(int delayMilliseconds)
|
||||
{
|
||||
Start(delayMilliseconds, 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="Start()" /> and will automatically call <see cref="Stop" /> after
|
||||
/// <paramref name="durationMilliseconds" /> milliseconds.
|
||||
/// </summary>
|
||||
/// <param name="durationMilliseconds">
|
||||
/// Allowed running time until <see cref="Stop" /> is automatically called, in milliseconds
|
||||
/// </param>
|
||||
public void StartAndRunForMilliseconds(int durationMilliseconds)
|
||||
{
|
||||
Start(0, durationMilliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines functionality of <see cref="StartAfterMilliseconds" /> and <see cref="StartAndRunForMilliseconds" />,
|
||||
/// allowing to <see cref="Start()" /> after a delay and run for a certain amount of time.
|
||||
/// </summary>
|
||||
/// <param name="delayMilliseconds">
|
||||
/// Delay in milliseconds before <see cref="Start()" /> is automatically called.
|
||||
/// </param>
|
||||
/// <param name="durationMilliseconds">
|
||||
/// Allowed running time starting after the initial delay until <see cref="Stop" /> is automatically called, in
|
||||
/// milliseconds.
|
||||
/// </param>
|
||||
public async void Start(int delayMilliseconds, int durationMilliseconds)
|
||||
{
|
||||
if (delayMilliseconds > 0)
|
||||
{
|
||||
Stop();
|
||||
_cts = new CancellationTokenSource(delayMilliseconds);
|
||||
await TaskExt.Delay(delayMilliseconds, _cts.Token);
|
||||
|
||||
if (_cts.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Stop();
|
||||
_cts = durationMilliseconds > 0 ? new CancellationTokenSource(durationMilliseconds) : new CancellationTokenSource();
|
||||
|
||||
StartInternal(_cts.Token, OnCompleted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the inner job.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (!IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cts.Cancel();
|
||||
_cts.Dispose();
|
||||
_cts = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a linked <see cref="CancellationTokenSource" /> using the internal controller token source.
|
||||
/// This allows to create token sources that will be cancelled if the controller gets cancelled.
|
||||
/// </summary>
|
||||
/// <returns>Linked cancellation token source</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The Task was not started, which means that there is no internal cancellation token source available yet. The Task
|
||||
/// must have been started to create a linked cancellation token source.
|
||||
/// </exception>
|
||||
public CancellationTokenSource CreateLinkedTokenSource()
|
||||
{
|
||||
if (_cts == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(GetType)}: Cannot create linked token source when Task is not running.");
|
||||
}
|
||||
|
||||
return CancellationTokenSource.CreateLinkedTokenSource(_cts.Token);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called when the application is about to quit. Ensures that the task is stopped.
|
||||
/// </summary>
|
||||
private void Application_quitting()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Event trigger for <see cref="Completed" />.
|
||||
/// </summary>
|
||||
private void OnCompleted()
|
||||
{
|
||||
if (_cts is { IsCancellationRequested: false })
|
||||
{
|
||||
Completed?.Invoke(this, EventArgs.Empty);
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Implements the internal logic between with <see cref="Start()" /> and <see cref="Stop" />.
|
||||
/// </summary>
|
||||
/// <param name="ct">
|
||||
/// Flags, with
|
||||
/// <see cref="CancellationToken.IsCancellationRequested" />, when <see cref="Stop" /> has been requested.
|
||||
/// </param>
|
||||
/// <param name="onCompleted">
|
||||
/// Optional callback when the logic has completed, so that the base class can free resources. The callback is only
|
||||
/// invoked if the logic fully completed. If the logic was stopped manually, the callback is not invoked.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// In case the implementation can finish on its own, please invoke <paramref name="onCompleted" /> instead of
|
||||
/// <see cref="Stop" />.
|
||||
/// </remarks>
|
||||
/// <seealso cref="UxrCancellableController" />
|
||||
protected abstract void StartInternal(CancellationToken ct, Action onCompleted);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbb124c0e0744e1e895b6ae566258881
|
||||
timeCreated: 1627554582
|
||||
@@ -0,0 +1,78 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrLoopController.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace UltimateXR.Core.Threading.TaskControllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A wrapper class to turn a cancelable action into a controllable <see cref="UxrCancellableController.Start()" />/
|
||||
/// <see cref="UxrCancellableController.Stop" /> pattern and run it uninterruptedly in a loop.
|
||||
/// </summary>
|
||||
public sealed class UxrLoopController : UxrCancellableController
|
||||
{
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="loopAction">
|
||||
/// A cancelable and loopable action that will be executing repeatedly until
|
||||
/// <see cref="UxrCancellableController.Stop" /> is called.
|
||||
/// </param>
|
||||
/// <param name="autoStartDelayMilliseconds">
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// If set, <paramref name="loopAction" /> starts looping after <paramref name="autoStartDelayMilliseconds" />
|
||||
/// milliseconds.
|
||||
/// </item>
|
||||
/// <item>If not set, <paramref name="loopAction" /> starts looping immediately.</item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
public UxrLoopController(Action<CancellationToken> loopAction, int autoStartDelayMilliseconds = -1)
|
||||
{
|
||||
_loopAction = loopAction;
|
||||
StartAfterMilliseconds(autoStartDelayMilliseconds);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Explicit conversion operator from <see cref="Action{CancellationToken}" /> to <see cref="UxrLoopController" />.
|
||||
/// </summary>
|
||||
/// <param name="loopAction">
|
||||
/// A cancelable and loopable action that will be executing repeatedly until
|
||||
/// <see cref="UxrCancellableController.Stop" /> is called.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new instance of <see cref="UxrLoopController" /> wrapping <paramref name="loopAction" />.
|
||||
/// </returns>
|
||||
public static explicit operator UxrLoopController(Action<CancellationToken> loopAction)
|
||||
{
|
||||
return new UxrLoopController(loopAction);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Overrides UxrCancellableController
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void StartInternal(CancellationToken ct, Action onCompleted)
|
||||
{
|
||||
_loopAction(ct); // Executes _loopAction until cancellation
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private readonly Action<CancellationToken> _loopAction;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d7e7222b7d24c9591199c3a739519d5
|
||||
timeCreated: 1627554582
|
||||
@@ -0,0 +1,113 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrTaskController.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UltimateXR.Core.Threading.TaskControllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A class that simplifies running tasks in Unity, taking care of stopping them automatically if an application quits
|
||||
/// or Unity exits playmode.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <para>
|
||||
/// UxrTaskController simplifies running the task and takes care of stopping it automatically if Unity or the
|
||||
/// application stops/quits.
|
||||
/// The constructor lets you start the task automatically, without requiring any further instructions, and also
|
||||
/// start/stop it manually if needed.
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// // An asynchronous task
|
||||
/// public async Task MyTask(int parameterA, CancellationToken ct)
|
||||
/// {
|
||||
/// await SomethingAsync(ct);
|
||||
/// }
|
||||
/// <br />
|
||||
/// // Create the task but don't start it yet (autoStart = false).
|
||||
/// UxrTaskController taskController = new UxrTaskController(ct => MyTask(10, ct), false);<br />
|
||||
/// <br />
|
||||
/// // Start the task manually. There are optional parameters for delayed start or forced duration.
|
||||
/// taskController.Start();<br />
|
||||
/// <br />
|
||||
/// // Stop the task manually at any point.
|
||||
/// taskController.Stop();
|
||||
/// </code>
|
||||
/// </example>
|
||||
public sealed class UxrTaskController : UxrCancellableController
|
||||
{
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="taskFunc">
|
||||
/// A cancelable task which that be executed asynchronously until completion or
|
||||
/// <see cref="UxrCancellableController.Stop" /> is called.
|
||||
/// </param>
|
||||
/// <param name="autoStart">
|
||||
/// <list type="bullet">
|
||||
/// <item>
|
||||
/// <term><see langword="false" />: </term>
|
||||
/// <description>
|
||||
/// <see cref="UxrCancellableController.Start()" /> needs to be called in order to start
|
||||
/// <paramref name="taskFunc" /> execution.
|
||||
/// </description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term><see langword="true" />: </term>
|
||||
/// <description><paramref name="taskFunc" /> starts executing immediately.</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
public UxrTaskController(Func<CancellationToken, Task> taskFunc, bool autoStart = false)
|
||||
{
|
||||
_taskFunc = taskFunc;
|
||||
if (autoStart)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Explicit conversion operator from <see cref="Func{CancellationToken,Task}" /> to <see cref="UxrTaskController" />.
|
||||
/// </summary>
|
||||
/// <param name="taskFunc">
|
||||
/// A cancelable task that will be executed asynchronously until completion or
|
||||
/// <see cref="UxrCancellableController.Stop" /> is called.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A new instance of <see cref="UxrTaskController" /> wrapping <paramref name="taskFunc" />.
|
||||
/// </returns>
|
||||
public static explicit operator UxrTaskController(Func<CancellationToken, Task> taskFunc)
|
||||
{
|
||||
return new UxrTaskController(taskFunc);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Overrides UxrCancellableController
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async void StartInternal(CancellationToken ct, Action onCompleted)
|
||||
{
|
||||
await _taskFunc(ct);
|
||||
onCompleted();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private readonly Func<CancellationToken, Task> _taskFunc;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d151491a5e3e4e9fb8f7faff1e776f2f
|
||||
timeCreated: 1621256057
|
||||
@@ -0,0 +1,102 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrMonoDispatcher.WorkDoubleBuffer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UltimateXR.Core.Threading
|
||||
{
|
||||
public sealed partial class UxrMonoDispatcher
|
||||
{
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// A double buffered working queue.
|
||||
/// </summary>
|
||||
private sealed class WorkDoubleBuffer
|
||||
{
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public WorkDoubleBuffer()
|
||||
{
|
||||
_input = new Queue<Action>();
|
||||
_output = new Queue<Action>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial input and output queue capacity</param>
|
||||
public WorkDoubleBuffer(int capacity)
|
||||
{
|
||||
_input = new Queue<Action>(capacity);
|
||||
_output = new Queue<Action>(capacity);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Executes all enqueued actions.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">
|
||||
/// A delegate callback throws an exception.
|
||||
/// </exception>
|
||||
public void Flush()
|
||||
{
|
||||
Switch();
|
||||
|
||||
foreach (var action in _output)
|
||||
{
|
||||
action?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a new action that should be executed.
|
||||
/// </summary>
|
||||
/// <param name="workItem">Action to execute</param>
|
||||
public void Enqueue(Action workItem)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_input.Enqueue(workItem);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Switches the buffers.
|
||||
/// </summary>
|
||||
private void Switch()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
(_output, _input) = (_input, _output);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
private Queue<Action> _input;
|
||||
private Queue<Action> _output;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 828c7fd865a74fbf93cc1eb280b9fdf7
|
||||
timeCreated: 1624656362
|
||||
@@ -0,0 +1,234 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrMonoDispatcher.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UltimateXR.Core.Components;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Extensions.System;
|
||||
using UltimateXR.Extensions.System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// A dispatcher that helps ensuring code runs on the main thread. Most Unity user functionality requires to be called
|
||||
/// from the main thread.
|
||||
/// </summary>
|
||||
public sealed partial class UxrMonoDispatcher : UxrComponent
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the caller is running on the main thread.
|
||||
/// </summary>
|
||||
public static bool IsCurrentThreadMain => !Application.isPlaying || s_mainThread == Thread.CurrentThread;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Runs code on the main thread.
|
||||
/// </summary>
|
||||
/// <param name="action">
|
||||
/// Action to execute.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="action" /> is <see langword="null" />
|
||||
/// </exception>
|
||||
/// <exception cref="Exception">
|
||||
/// A delegate callback throws an exception.
|
||||
/// </exception>
|
||||
public static void RunOnMainThread(Action action)
|
||||
{
|
||||
action.ThrowIfNull(nameof(action));
|
||||
|
||||
if (!Application.isPlaying || Thread.CurrentThread == s_mainThread)
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
Instance.Enqueue(action);
|
||||
Instance.StartDispatching();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs code on the main thread.
|
||||
/// </summary>
|
||||
/// <param name="actions">
|
||||
/// An variable set of actions that will run on the main thread sequentially.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <paramref name="actions" /> is <see langword="null" />
|
||||
/// </exception>
|
||||
/// <exception cref="Exception">
|
||||
/// A delegate callback throws an exception.
|
||||
/// </exception>
|
||||
public static void RunOnMainThread(params Action[] actions)
|
||||
{
|
||||
if (!Application.isPlaying || Thread.CurrentThread == s_mainThread)
|
||||
{
|
||||
foreach (Action action in actions)
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Action action in actions)
|
||||
{
|
||||
Instance.Enqueue(action);
|
||||
}
|
||||
|
||||
Instance.StartDispatching();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs code on the main thread, asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="ct">
|
||||
/// Cancellation token that allows to cancel the task.
|
||||
/// </param>
|
||||
/// <param name="action">
|
||||
/// The action to execute.
|
||||
/// </param>
|
||||
/// <exception cref="Exception">
|
||||
/// A delegate callback throws an exception.
|
||||
/// </exception>
|
||||
/// <returns>
|
||||
/// An awaitable <see cref="Task" /> that finishes when the operation finished.
|
||||
/// </returns>
|
||||
public static Task RunOnMainThreadAsync(CancellationToken ct, Action action)
|
||||
{
|
||||
if (ct.IsCancellationRequested)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (!Application.isPlaying || Thread.CurrentThread == s_mainThread)
|
||||
{
|
||||
action();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Instance.Enqueue(action);
|
||||
return Instance.DispatchAsync(ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (s_instance is null)
|
||||
{
|
||||
s_instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Relevant)
|
||||
{
|
||||
Debug.Log($"{UxrConstants.CoreModule} {nameof(UxrMonoDispatcher)} singleton successfully initialized on Awake", this);
|
||||
}
|
||||
}
|
||||
else if (!ReferenceEquals(s_instance, this))
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Warnings)
|
||||
{
|
||||
Debug.LogWarning($"{UxrConstants.CoreModule} {nameof(UxrMonoDispatcher)} singleton already initialized. Destroying secondary instance on Awake", this);
|
||||
}
|
||||
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the queue, executing all remaining actions, and disables the component.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_workQueue.Flush();
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the singleton.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Initialize()
|
||||
{
|
||||
s_mainThread = Thread.CurrentThread;
|
||||
s_instance = FindObjectOfType<UxrMonoDispatcher>();
|
||||
if (!(s_instance is null))
|
||||
{
|
||||
Debug.Log($"[{nameof(UxrMonoDispatcher)} singleton successfully found in scene.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatches the current actions.
|
||||
/// </summary>
|
||||
/// <param name="ct">Cancellation token</param>
|
||||
/// <returns>Awaitable <see cref="Task" /> that finishes when the actions were dispatched</returns>
|
||||
private Task DispatchAsync(CancellationToken ct)
|
||||
{
|
||||
StartDispatching();
|
||||
return TaskExt.WaitWhile(() => IsDispatching, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a new action.
|
||||
/// </summary>
|
||||
/// <param name="workItem">Action to enqueue</param>
|
||||
private void Enqueue(Action workItem)
|
||||
{
|
||||
_workQueue.Enqueue(workItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the component so that it starts dispatching the enqueued actions.
|
||||
/// </summary>
|
||||
private void StartDispatching()
|
||||
{
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton.
|
||||
/// </summary>
|
||||
private static UxrMonoDispatcher Instance => s_instance ? s_instance : s_instance = new GameObject(nameof(UxrMonoDispatcher)).AddComponent<UxrMonoDispatcher>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether it is currently dispatching.
|
||||
/// </summary>
|
||||
private bool IsDispatching => enabled;
|
||||
|
||||
private static UxrMonoDispatcher s_instance;
|
||||
private static Thread s_mainThread;
|
||||
private readonly WorkDoubleBuffer _workQueue = new WorkDoubleBuffer(8);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2eb59326e7404032b2825f4e4a993981
|
||||
timeCreated: 1611659570
|
||||
Reference in New Issue
Block a user