Initialer Upload neues Unity-Projekt

This commit is contained in:
Daniel Ocks
2025-07-21 09:11:14 +02:00
commit eeca72985b
14558 changed files with 1508140 additions and 0 deletions

View File

@ -0,0 +1,539 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
internal static class OVRTask
{
internal static OVRTask<TResult> FromGuid<TResult>(Guid id) => Create<TResult>(id);
internal static OVRTask<TResult> FromRequest<TResult>(ulong id) => Create<TResult>(GetId(id));
internal static OVRTask<TResult> FromResult<TResult>(TResult result)
{
var task = Create<TResult>(Guid.NewGuid());
task.SetResult(result);
return task;
}
internal static OVRTask<TResult> GetExisting<TResult>(Guid id) => Get<TResult>(id);
internal static OVRTask<TResult> GetExisting<TResult>(ulong id) => Get<TResult>(GetId(id));
internal static void SetResult<TResult>(Guid id, TResult result) =>
GetExisting<TResult>(id).SetResult(result);
internal static void SetResult<TResult>(ulong id, TResult result) =>
GetExisting<TResult>(id).SetResult(result);
private static OVRTask<TResult> Get<TResult>(Guid id)
{
return new OVRTask<TResult>(id);
}
private static OVRTask<TResult> Create<TResult>(Guid id)
{
var task = Get<TResult>(id);
task.AddToPending();
return task;
}
internal static unsafe Guid GetId(ulong value)
{
const ulong hashModifier1 = 0x319642b2d24d8ec3;
const ulong hashModifier2 = 0x96de1b173f119089;
var guid = default(Guid);
*(ulong*)&guid = unchecked(value + hashModifier1);
*((ulong*)&guid + 1) = hashModifier2;
return guid;
}
}
/// <summary>
/// Represents an awaitable task.
/// </summary>
/// <remarks>
/// This is a task-like object which supports the <c>await</c> pattern. Typically, you do not need to
/// create or use this object directly. Instead, you can either :
/// <para>- <c>await</c> a method which returns an object of type <see cref="OVRTask{TResult}"/>,
/// which will eventually return a <typeparamref name="TResult"/></para>
/// <para>- poll the <see cref="IsCompleted"/> property and then call <see cref="GetResult"/></para>
/// <para>- pass a delegate by calling <see cref="ContinueWith(Action{TResult})"/>. Note that an additional state <c>object</c> can get passed in and added as a parameter of the callback, see <see cref="ContinueWith{T}"/></para>
/// Requires the main thread to complete the await contract - blocking can result in an infinite loop.
/// </remarks>
/// <typeparam name="TResult">The type of result being awaited.</typeparam>
public readonly struct OVRTask<TResult> : IEquatable<OVRTask<TResult>>, IDisposable
{
#region static
private static readonly HashSet<Guid> Pending = new HashSet<Guid>();
private static readonly Dictionary<Guid, TResult> Results = new Dictionary<Guid, TResult>();
private static readonly Dictionary<Guid, Action> Continuations = new Dictionary<Guid, Action>();
private delegate void CallbackInvoker(Guid guid, TResult result);
private delegate bool CallbackRemover(Guid guid);
private static readonly Dictionary<Guid, CallbackInvoker>
CallbackInvokers = new Dictionary<Guid, CallbackInvoker>();
private static readonly Dictionary<Guid, CallbackRemover>
CallbackRemovers = new Dictionary<Guid, CallbackRemover>();
private static readonly HashSet<Action> CallbackClearers = new HashSet<Action>();
private delegate bool InternalDataRemover(Guid guid);
private static readonly Dictionary<Guid, InternalDataRemover> InternalDataRemovers =
new Dictionary<Guid, InternalDataRemover>();
private static readonly HashSet<Action> InternalDataClearers = new HashSet<Action>();
private static readonly Dictionary<Guid, Action<Guid>> SubscriberRemovers =
new Dictionary<Guid, Action<Guid>>();
private static readonly HashSet<Action> SubscriberClearers = new HashSet<Action>();
#endregion
private readonly Guid _id;
internal OVRTask(Guid id)
{
_id = id;
}
internal void AddToPending() => Pending.Add(_id);
internal bool IsPending => Pending.Contains(_id);
internal void SetInternalData<T>(T data) => InternalData<T>.Set(_id, data);
internal bool TryGetInternalData<T>(out T data) => InternalData<T>.TryGet(_id, out data);
internal void SetResult(TResult result)
{
// Means no one was awaiting this result.
if (!Pending.Remove(_id)) return;
if (InternalDataRemovers.TryGetValue(_id, out var internalDataRemover))
{
InternalDataRemovers.Remove(_id);
internalDataRemover(_id);
}
if (SubscriberRemovers.TryGetValue(_id, out var subscriberRemover))
{
SubscriberRemovers.Remove(_id);
subscriberRemover(_id);
}
if (CallbackInvokers.TryGetValue(_id, out var invoker))
{
CallbackInvokers.Remove(_id);
invoker(_id, result);
}
else
{
// Add to the results so that GetResult can retrieve it later.
Results.Add(_id, result);
if (Continuations.TryGetValue(_id, out var continuation))
{
Continuations.Remove(_id);
continuation();
}
}
}
private static class InternalData<T>
{
private static readonly Dictionary<Guid, T> Data = new Dictionary<Guid, T>();
public static bool TryGet(Guid taskId, out T data)
{
return Data.TryGetValue(taskId, out data);
}
public static void Set(Guid taskId, T data)
{
Data[taskId] = data;
InternalDataRemovers.Add(taskId, Remover);
InternalDataClearers.Add(Clearer);
}
private static readonly InternalDataRemover Remover = Remove;
private static readonly Action Clearer = Clear;
private static bool Remove(Guid taskId) => Data.Remove(taskId);
private static void Clear() => Data.Clear();
}
static class IncrementalResultSubscriber<T>
{
static readonly Dictionary<Guid, Action<T>> Subscribers = new Dictionary<Guid, Action<T>>();
public static void Set(Guid taskId, Action<T> subscriber)
{
Subscribers[taskId] = subscriber;
SubscriberRemovers[taskId] = Remover;
SubscriberClearers.Add(Clearer);
}
public static void Notify(Guid taskId, T result)
{
if (Subscribers.TryGetValue(taskId, out var subscriber))
{
subscriber(result);
}
}
static readonly Action<Guid> Remover = Remove;
static void Remove(Guid id) => Subscribers.Remove(id);
static readonly Action Clearer = Clear;
static void Clear() => Subscribers.Clear();
}
/// <summary>
/// Sets the delegate to be invoked when an incremental result is available before the task is complete.
/// </summary>
/// <remarks>
/// Some tasks may provide incremental results before the task is complete. In this case, you can use
/// <see cref="SetIncrementalResultCallback{TIncrementalResult}"/> to receive those results as they become available.
///
/// For example, the task may provide a list of results over some period of time and may be able to provide
/// partial results as they become available, before the task completes.
/// </remarks>
/// <param name="onIncrementalResultAvailable">Invoked whenever <see cref="NotifyIncrementalResult{TIncrementalResult}"/>
/// is called.</param>
/// <typeparam name="TIncrementalResult">The type of the incremental result. This is typically different than the
/// <typeparamref name="TResult"/>.</typeparam>
/// <exception cref="System.ArgumentNullException">Thrown when <paramref name="onIncrementalResultAvailable"/> is `null`.</exception>
internal void SetIncrementalResultCallback<TIncrementalResult>(
Action<TIncrementalResult> onIncrementalResultAvailable)
{
if (onIncrementalResultAvailable == null)
throw new ArgumentNullException(nameof(onIncrementalResultAvailable));
IncrementalResultSubscriber<TIncrementalResult>.Set(_id, onIncrementalResultAvailable);
}
/// <summary>
/// Notifies a subscriber of an incremental result associated with an ongoing task.
/// </summary>
/// <remarks>
/// Use this to provide partial results that may be available before the task fully completes.
/// </remarks>
/// <typeparam name="TIncrementalResult">The type of the result, usually different from <typeparamref name="TResult"/>.</typeparam>
internal void NotifyIncrementalResult<TIncrementalResult>(TIncrementalResult incrementalResult)
=> IncrementalResultSubscriber<TIncrementalResult>.Notify(_id, incrementalResult);
#region Polling Implementation
/// <summary>
/// Indicates whether the task has completed.
/// </summary>
/// <remarks>
/// Choose only one pattern out of the three proposed way of awaiting for the task completion:
/// Polling,<c>async/await</c> or <see cref="ContinueWith(Action{TResult})"/>
/// as all three patterns will end up calling the <see cref="GetResult"/> which can only be called once.
/// </remarks>
/// <returns><c>True</c> if the task has completed. <see cref="GetResult"/> can be called.</returns>
public bool IsCompleted => !IsPending;
/// <summary>
/// Gets the result of the Task.
/// </summary>
/// <remarks>
/// This method should only be called once <see cref="IsCompleted"/> is true.
/// Calling it multiple times leads to undefined behavior.
/// Do not use in conjunction with any other methods (<c>await</c> or using <see cref="ContinueWith"/>).
/// </remarks>
/// <returns>Returns the result of type <typeparamref name="TResult"/>.</returns>
/// <exception cref="InvalidOperationException">Thrown when the task doesn't have any available result. This could
/// happen if the method is called before <see cref="IsCompleted"/> is true, after the task has been disposed of
/// or if this method has already been called once.</exception>
public TResult GetResult()
{
if (!Results.TryGetValue(_id, out var value))
{
throw new InvalidOperationException($"Task {_id} doesn't have any available result.");
}
Results.Remove(_id);
return value;
}
#endregion
#region Awaiter Contract Implementation
/// <summary>
/// Definition of an awaiter that satisfies the await contract.
/// </summary>
/// <remarks>
/// This allows an <see cref="OVRTask{T}"/> to be awaited using the <c>await</c> keyword.
/// Typically, you should not use this struct; instead, it is used by the compiler by
/// automatically calling the <see cref="GetAwaiter"/> method when using the <c>await</c> keyword.
/// </remarks>
public readonly struct Awaiter : INotifyCompletion
{
private readonly OVRTask<TResult> _task;
internal Awaiter(OVRTask<TResult> task)
{
_task = task;
}
public bool IsCompleted => _task.IsCompleted;
public void OnCompleted(Action continuation) => _task.WithContinuation(continuation);
public TResult GetResult() => _task.GetResult();
}
/// <summary>
/// Gets an awaiter that satisfies the await contract.
/// </summary>
/// <remarks>
/// This allows an <see cref="OVRTask{T}"/> to be awaited using the <c>await</c> keyword.
/// Typically, you should not call this directly; instead, it is invoked by the compiler, e.g.,
/// <example>
/// <code><![CDATA[
/// // Something that returns an OVRTask<T>
/// var task = GetResultAsync();
///
/// // compiler uses GetAwaiter here
/// var result = await task;
/// ]]></code>
/// Or, more commonly:
/// <code><![CDATA[
/// var result = await GetResultAsync();
/// ]]></code>
/// </example>
/// Requires the main thread to complete the await contract - blocking can result in an infinite loop.
/// </remarks>
/// <returns>Returns an Awaiter-like object that satisfies the await pattern.</returns>
public Awaiter GetAwaiter() => new Awaiter(this);
private void WithContinuation(Action continuation)
{
ValidateDelegateAndThrow(continuation, nameof(continuation));
Continuations[_id] = continuation;
}
#endregion
#region Delegate Implementation
readonly struct Callback
{
private static readonly Dictionary<Guid, Callback> Callbacks = new Dictionary<Guid, Callback>();
readonly Action<TResult> _delegate;
static void Invoke(Guid taskId, TResult result)
{
if (Callbacks.TryGetValue(taskId, out var callback))
{
Callbacks.Remove(taskId);
callback.Invoke(result);
}
}
static bool Remove(Guid taskId) => Callbacks.Remove(taskId);
static void Clear() => Callbacks.Clear();
void Invoke(TResult result) => _delegate(result);
Callback(Action<TResult> @delegate) => _delegate = @delegate;
public static readonly CallbackInvoker Invoker = Invoke;
public static readonly CallbackRemover Remover = Remove;
public static readonly Action Clearer = Clear;
public static void Add(Guid taskId, Action<TResult> @delegate)
{
Callbacks.Add(taskId, new Callback(@delegate));
CallbackInvokers.Add(taskId, Invoker);
CallbackRemovers.Add(taskId, Remover);
CallbackClearers.Add(Clearer);
}
}
readonly struct CallbackWithState<T>
{
private static readonly Dictionary<Guid, CallbackWithState<T>> Callbacks =
new Dictionary<Guid, CallbackWithState<T>>();
readonly T _data;
readonly Action<TResult, T> _delegate;
static void Invoke(Guid taskId, TResult result)
{
if (Callbacks.TryGetValue(taskId, out var callback))
{
Callbacks.Remove(taskId);
callback.Invoke(result);
}
}
CallbackWithState(T data, Action<TResult, T> @delegate)
{
_data = data;
_delegate = @delegate;
}
private static readonly CallbackInvoker Invoker = Invoke;
private static readonly CallbackRemover Remover = Remove;
private static readonly Action Clearer = Clear;
private static void Clear() => Callbacks.Clear();
private static bool Remove(Guid taskId) => Callbacks.Remove(taskId);
private void Invoke(TResult result) => _delegate(result, _data);
public static void Add(Guid taskId, T data, Action<TResult, T> callback)
{
Callbacks.Add(taskId, new CallbackWithState<T>(data, callback));
CallbackInvokers.Add(taskId, Invoker);
CallbackRemovers.Add(taskId, Remover);
CallbackClearers.Add(Clearer);
}
}
/// <summary>
/// Registers a delegate that will get called on completion of the task.
/// </summary>
/// <remarks>
/// The delegate will be invoked with the <typeparamref name="TResult"/> result as parameter.
/// Do not use in conjunction with any other methods (<c>await</c> or calling <see cref="GetResult"/>).
/// </remarks>
/// <param name="onCompleted">A delegate to be invoked when this task completes. If the task is already complete,
/// <paramref name="onCompleted"/> is invoked immediately.</param>
/// <seealso cref="ContinueWith{T}"/>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="onCompleted"/> is null.</exception>
/// <exception cref="InvalidOperationException">Thrown if there already is a delegate or a continuation registered to this task.</exception>
public void ContinueWith(Action<TResult> onCompleted)
{
ValidateDelegateAndThrow(onCompleted, nameof(onCompleted));
if (IsCompleted)
{
onCompleted.Invoke(GetResult());
}
else
{
Callback.Add(_id, onCompleted);
}
}
/// <summary>
/// Registers a delegate that will get called on completion of the task.
/// </summary>
/// <remarks>
/// The delegate will be invoked with <paramref name="state"/> and the <typeparamref name="TResult"/> result as
/// parameters.
/// Do not use in conjunction with any other methods (<c>await</c> or calling <see cref="GetResult"/>).
/// </remarks>
/// <param name="onCompleted">A delegate to be invoked when this task completes. If the task is already complete,
/// <paramref name="onCompleted"/> is invoked immediately.</param>
/// <param name="state">An <c>object</c> to store and pass to <paramref name="onCompleted"/>.</param>
/// <seealso cref="ContinueWith(Action{TResult})"/>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="onCompleted"/> is null.</exception>
/// <exception cref="InvalidOperationException">Thrown if there already is a delegate or a continuation registered to this task.</exception>
public void ContinueWith<T>(Action<TResult, T> onCompleted, T state)
{
ValidateDelegateAndThrow(onCompleted, nameof(onCompleted));
if (IsCompleted)
{
onCompleted.Invoke(GetResult(), state);
}
else
{
CallbackWithState<T>.Add(_id, state, onCompleted);
}
}
void ValidateDelegateAndThrow(object @delegate, string paramName)
{
if (@delegate == null)
throw new ArgumentNullException(paramName);
if (Continuations.ContainsKey(_id))
throw new InvalidOperationException($"Task {_id} is already being used by an await call.");
if (CallbackInvokers.ContainsKey(_id))
throw new InvalidOperationException($"Task {_id} is already being used with ContinueWith.");
}
#endregion
#region IDisposable Implementation
/// <summary>
/// Disposes of the task.
/// </summary>
/// <remarks>
/// Invalidate this object but does not cancel the task.
/// In the case where the result will not actually be consumed, it must be called to prevent a memory leak.
/// You can not call <see cref="GetResult"/> nor use <c>await</c> on a disposed task.
/// </remarks>
public void Dispose()
{
Results.Remove(_id);
Continuations.Remove(_id);
Pending.Remove(_id);
CallbackInvokers.Remove(_id);
if (CallbackRemovers.TryGetValue(_id, out var remover))
{
CallbackRemovers.Remove(_id);
remover(_id);
}
if (InternalDataRemovers.TryGetValue(_id, out var internalDataRemover))
{
InternalDataRemovers.Remove(_id);
internalDataRemover(_id);
}
if (SubscriberRemovers.TryGetValue(_id, out var subscriberRemover))
{
SubscriberRemovers.Remove(_id);
subscriberRemover(_id);
}
}
#endregion
#region IEquatable Implementation
public bool Equals(OVRTask<TResult> other) => _id == other._id;
public override bool Equals(object obj) => obj is OVRTask<TResult> other && Equals(other);
public static bool operator ==(OVRTask<TResult> lhs, OVRTask<TResult> rhs) => lhs.Equals(rhs);
public static bool operator !=(OVRTask<TResult> lhs, OVRTask<TResult> rhs) => !lhs.Equals(rhs);
public override int GetHashCode() => _id.GetHashCode();
public override string ToString() => _id.ToString();
#endregion
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7bc71515869d46e08e210173388da05c
timeCreated: 1669731273