Add AsyncReactiveProperty
parent
859eaa2278
commit
ee58aab0a9
|
@ -28,6 +28,7 @@
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.uGUI.cs;
|
||||||
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityAsyncExtensions.MonoBehaviour.cs;
|
||||||
|
..\UniTask\Assets\Plugins\UniTask\Runtime\UnityBindingExtensions.cs;
|
||||||
" />
|
" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public interface IAsyncReadOnlyReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
||||||
|
{
|
||||||
|
T Value { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAsyncReactiveProperty<T> : IAsyncReadOnlyReactiveProperty<T>
|
||||||
|
{
|
||||||
|
new T Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class AsyncReactiveProperty<T> : IUniTaskAsyncEnumerable<T>, IDisposable
|
||||||
|
{
|
||||||
|
TriggerEvent<T> triggerEvent;
|
||||||
|
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
[UnityEngine.SerializeField]
|
||||||
|
#endif
|
||||||
|
T latestValue;
|
||||||
|
|
||||||
|
public T Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return latestValue;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.latestValue = value;
|
||||||
|
triggerEvent.SetResult(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncReactiveProperty(T value)
|
||||||
|
{
|
||||||
|
this.latestValue = value;
|
||||||
|
this.triggerEvent = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new Enumerator(this, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
triggerEvent.SetCanceled(CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
||||||
|
{
|
||||||
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
readonly AsyncReactiveProperty<T> parent;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
T value;
|
||||||
|
bool isDisposed;
|
||||||
|
|
||||||
|
public Enumerator(AsyncReactiveProperty<T> parent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
parent.triggerEvent.Add(this);
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
|
||||||
|
if (cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Current => value;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (!isDisposed)
|
||||||
|
{
|
||||||
|
isDisposed = true;
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
completionSource.TrySetCanceled(cancellationToken);
|
||||||
|
parent.triggerEvent.Remove(this);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetResult(T value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (Enumerator)state;
|
||||||
|
self.DisposeAsync().Forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8ef320b87f537ee4fb2282e765dc6166
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,229 @@
|
||||||
|
using Cysharp.Threading.Tasks.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public interface ITriggerEvent<T>
|
||||||
|
{
|
||||||
|
void SetResult(T value);
|
||||||
|
void SetCanceled(CancellationToken cancellationToken);
|
||||||
|
void Add(IResolveCancelPromise<T> handler);
|
||||||
|
void Remove(IResolveCancelPromise<T> handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// be careful to use, itself is struct.
|
||||||
|
public struct TriggerEvent<T> : ITriggerEvent<T>
|
||||||
|
{
|
||||||
|
// optimize: many cases, handler is single.
|
||||||
|
IResolveCancelPromise<T> singleHandler;
|
||||||
|
|
||||||
|
IResolveCancelPromise<T>[] handlers;
|
||||||
|
|
||||||
|
// when running(in TrySetResult), does not add immediately.
|
||||||
|
bool isRunning;
|
||||||
|
IResolveCancelPromise<T> waitHandler;
|
||||||
|
MinimumQueue<IResolveCancelPromise<T>> waitQueue;
|
||||||
|
|
||||||
|
public void SetResult(T value)
|
||||||
|
{
|
||||||
|
isRunning = true;
|
||||||
|
|
||||||
|
if (singleHandler != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
singleHandler.TrySetResult(value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
#else
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handlers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < handlers.Length; i++)
|
||||||
|
{
|
||||||
|
if (handlers[i] != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handlers[i].TrySetResult(value);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
handlers[i] = null;
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
#else
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isRunning = false;
|
||||||
|
|
||||||
|
if (waitHandler != null)
|
||||||
|
{
|
||||||
|
var h = waitHandler;
|
||||||
|
waitHandler = null;
|
||||||
|
Add(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitQueue != null)
|
||||||
|
{
|
||||||
|
while (waitQueue.Count != 0)
|
||||||
|
{
|
||||||
|
Add(waitQueue.Dequeue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCanceled(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
isRunning = true;
|
||||||
|
|
||||||
|
if (singleHandler != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
((ICancelPromise)singleHandler).TrySetCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
#else
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handlers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < handlers.Length; i++)
|
||||||
|
{
|
||||||
|
if (handlers[i] != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
((ICancelPromise)handlers[i]).TrySetCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
#else
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
#endif
|
||||||
|
handlers[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isRunning = false;
|
||||||
|
|
||||||
|
if (waitHandler != null)
|
||||||
|
{
|
||||||
|
var h = waitHandler;
|
||||||
|
waitHandler = null;
|
||||||
|
Add(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitQueue != null)
|
||||||
|
{
|
||||||
|
while (waitQueue.Count != 0)
|
||||||
|
{
|
||||||
|
Add(waitQueue.Dequeue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(IResolveCancelPromise<T> handler)
|
||||||
|
{
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
if (waitHandler == null)
|
||||||
|
{
|
||||||
|
waitHandler = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitQueue == null)
|
||||||
|
{
|
||||||
|
waitQueue = new MinimumQueue<IResolveCancelPromise<T>>(4);
|
||||||
|
}
|
||||||
|
waitQueue.Enqueue(handler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (singleHandler == null)
|
||||||
|
{
|
||||||
|
singleHandler = handler;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (handlers == null)
|
||||||
|
{
|
||||||
|
handlers = new IResolveCancelPromise<T>[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
// check empty
|
||||||
|
for (int i = 0; i < handlers.Length; i++)
|
||||||
|
{
|
||||||
|
if (handlers[i] == null)
|
||||||
|
{
|
||||||
|
handlers[i] = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// full, ensure capacity
|
||||||
|
var last = handlers.Length;
|
||||||
|
{
|
||||||
|
EnsureCapacity(ref handlers);
|
||||||
|
handlers[last] = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EnsureCapacity(ref IResolveCancelPromise<T>[] array)
|
||||||
|
{
|
||||||
|
var newSize = array.Length * 2;
|
||||||
|
var newArray = new IResolveCancelPromise<T>[newSize];
|
||||||
|
Array.Copy(array, 0, newArray, 0, array.Length);
|
||||||
|
array = newArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(IResolveCancelPromise<T> handler)
|
||||||
|
{
|
||||||
|
if (singleHandler == handler)
|
||||||
|
{
|
||||||
|
singleHandler = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (handlers != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < handlers.Length; i++)
|
||||||
|
{
|
||||||
|
if (handlers[i] == handler)
|
||||||
|
{
|
||||||
|
// fill null.
|
||||||
|
handlers[i] = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f68b22bb8f66f5c4885f9bd3c4fc43ed
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
|
||||||
using Cysharp.Threading.Tasks.Linq;
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -25,7 +24,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
if (calledDestroy) return;
|
if (calledDestroy) return;
|
||||||
calledDestroy = true;
|
calledDestroy = true;
|
||||||
|
|
||||||
triggerEvent.TrySetCanceled(CancellationToken.None);
|
triggerEvent.SetCanceled(CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddHandler(IResolveCancelPromise<T> handler)
|
internal void AddHandler(IResolveCancelPromise<T> handler)
|
||||||
|
@ -50,7 +49,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
|
|
||||||
protected void RaiseEvent(T value)
|
protected void RaiseEvent(T value)
|
||||||
{
|
{
|
||||||
triggerEvent.TrySetResult(value);
|
triggerEvent.SetResult(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
@ -284,207 +283,4 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
core.OnCompleted(continuation, state, token);
|
core.OnCompleted(continuation, state, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// be careful to use, itself is struct.
|
|
||||||
public struct TriggerEvent<T>
|
|
||||||
{
|
|
||||||
// optimize: many cases, handler is single.
|
|
||||||
IResolveCancelPromise<T> singleHandler;
|
|
||||||
|
|
||||||
IResolveCancelPromise<T>[] handlers;
|
|
||||||
|
|
||||||
// when running(in TrySetResult), does not add immediately.
|
|
||||||
bool isRunning;
|
|
||||||
IResolveCancelPromise<T> waitHandler;
|
|
||||||
MinimumQueue<IResolveCancelPromise<T>> waitQueue;
|
|
||||||
|
|
||||||
public bool TrySetResult(T value)
|
|
||||||
{
|
|
||||||
isRunning = true;
|
|
||||||
|
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
singleHandler.TrySetResult(value);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.LogException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handlers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
|
||||||
if (handlers[i] != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handlers[i].TrySetResult(value);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
handlers[i] = null;
|
|
||||||
Debug.LogException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
|
||||||
Add(waitQueue.Dequeue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TrySetCanceled(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
isRunning = true;
|
|
||||||
|
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
((ICancelPromise)singleHandler).TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.LogException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handlers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
|
||||||
if (handlers[i] != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
((ICancelPromise)handlers[i]).TrySetCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.LogException(ex);
|
|
||||||
handlers[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
|
||||||
Add(waitQueue.Dequeue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(IResolveCancelPromise<T> handler)
|
|
||||||
{
|
|
||||||
if (isRunning)
|
|
||||||
{
|
|
||||||
if (waitHandler == null)
|
|
||||||
{
|
|
||||||
waitHandler = handler;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue == null)
|
|
||||||
{
|
|
||||||
waitQueue = new MinimumQueue<IResolveCancelPromise<T>>(4);
|
|
||||||
}
|
|
||||||
waitQueue.Enqueue(handler);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (singleHandler == null)
|
|
||||||
{
|
|
||||||
singleHandler = handler;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (handlers == null)
|
|
||||||
{
|
|
||||||
handlers = new IResolveCancelPromise<T>[4];
|
|
||||||
}
|
|
||||||
|
|
||||||
// check empty
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
|
||||||
if (handlers[i] == null)
|
|
||||||
{
|
|
||||||
handlers[i] = handler;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// full, ensure capacity
|
|
||||||
var last = handlers.Length;
|
|
||||||
{
|
|
||||||
EnsureCapacity(ref handlers);
|
|
||||||
handlers[last] = handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EnsureCapacity(ref IResolveCancelPromise<T>[] array)
|
|
||||||
{
|
|
||||||
var newSize = array.Length * 2;
|
|
||||||
var newArray = new IResolveCancelPromise<T>[newSize];
|
|
||||||
Array.Copy(array, 0, newArray, 0, array.Length);
|
|
||||||
array = newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(IResolveCancelPromise<T> handler)
|
|
||||||
{
|
|
||||||
if (singleHandler == handler)
|
|
||||||
{
|
|
||||||
singleHandler = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (handlers != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
|
||||||
if (handlers[i] == handler)
|
|
||||||
{
|
|
||||||
// fill null.
|
|
||||||
handlers[i] = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "UniTask",
|
"name": "UniTask",
|
||||||
"references": [
|
"references": [
|
||||||
"Unity.ResourceManager"
|
"Unity.ResourceManager",
|
||||||
|
"Unity.TextMeshPro"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
@ -15,6 +16,11 @@
|
||||||
"name": "com.unity.addressables",
|
"name": "com.unity.addressables",
|
||||||
"expression": "",
|
"expression": "",
|
||||||
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
"define": "UNITASK_ADDRESSABLE_SUPPORT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "com.unity.textmeshpro",
|
||||||
|
"expression": "",
|
||||||
|
"define": "UNITASK_TEXTMESHPRO_SUPPORT"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"noEngineReferences": false
|
"noEngineReferences": false
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public static class UnityBindingExtensions
|
||||||
|
{
|
||||||
|
// <string> -> Text
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
text.text = e.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <T> -> Text
|
||||||
|
|
||||||
|
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo<T>(this IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo<T>(this AsyncReactiveProperty<T> source, Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore<T>(IUniTaskAsyncEnumerable<T> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
text.text = e.Current.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <bool> -> Selectable
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<bool> source, Selectable selectable, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, selectable, selectable.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<bool> source, Selectable selectable, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, selectable, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<bool> source, Selectable selectable, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
|
||||||
|
selectable.interactable = e.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TMP
|
||||||
|
|
||||||
|
#if UNITASK_TEXTMESHPRO_SUPPORT
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, TMPro.TMP_Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
text.text = e.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 090b20e3528552b4a8d751f7df525c2b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -14,6 +14,7 @@ using Unity.Jobs;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using TMPro;
|
||||||
|
|
||||||
public struct MyJob : IJob
|
public struct MyJob : IJob
|
||||||
{
|
{
|
||||||
|
@ -39,187 +40,9 @@ public enum MyEnum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface IAsyncReadOnlyReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
T Value { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public interface IAsyncReactiveProperty<T> : IAsyncReadOnlyReactiveProperty<T>
|
|
||||||
{
|
|
||||||
new T Value { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public struct AsyncValueReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
|
||||||
{
|
|
||||||
TriggerEvent<T> triggerEvent;
|
|
||||||
|
|
||||||
[SerializeField]
|
|
||||||
T latestValue;
|
|
||||||
|
|
||||||
public T Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return latestValue;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
this.latestValue = value;
|
|
||||||
triggerEvent.TrySetResult(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncValueReactiveProperty(T value)
|
|
||||||
{
|
|
||||||
this.latestValue = value;
|
|
||||||
this.triggerEvent = default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return new Enumerator(triggerEvent, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
|
||||||
{
|
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
|
||||||
|
|
||||||
readonly TriggerEvent<T> triggerEvent;
|
|
||||||
readonly CancellationToken cancellationToken;
|
|
||||||
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
|
||||||
T value;
|
|
||||||
|
|
||||||
public Enumerator(TriggerEvent<T> triggerEvent, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
this.triggerEvent = triggerEvent;
|
|
||||||
this.cancellationToken = cancellationToken;
|
|
||||||
|
|
||||||
triggerEvent.Add(this);
|
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
|
||||||
{
|
|
||||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => value;
|
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
|
||||||
{
|
|
||||||
completionSource.Reset();
|
|
||||||
return new UniTask<bool>(this, completionSource.Version);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask DisposeAsync()
|
|
||||||
{
|
|
||||||
triggerEvent.TrySetCanceled(cancellationToken);
|
|
||||||
triggerEvent.Remove(this);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TrySetResult(T value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
return triggerEvent.TrySetResult(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
DisposeAsync().Forget();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CancellationCallback(object state)
|
|
||||||
{
|
|
||||||
var self = (Enumerator)state;
|
|
||||||
self.DisposeAsync().Forget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static partial class UnityUIComponentExtensions
|
public static partial class UnityUIComponentExtensions
|
||||||
{
|
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
|
||||||
{
|
|
||||||
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
|
||||||
{
|
|
||||||
var repeat = false;
|
|
||||||
BIND_AGAIN:
|
|
||||||
var e = source.GetAsyncEnumerator(cancellationToken);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
bool moveNext;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
moveNext = await e.MoveNextAsync();
|
|
||||||
repeat = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (ex is OperationCanceledException) return;
|
|
||||||
|
|
||||||
if (rebindOnError && !repeat)
|
|
||||||
{
|
|
||||||
repeat = true;
|
|
||||||
if (e != null)
|
|
||||||
{
|
|
||||||
await e.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
goto BIND_AGAIN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moveNext) return;
|
|
||||||
|
|
||||||
text.text = e.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (e != null)
|
|
||||||
{
|
|
||||||
await e.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
|
|
||||||
//{
|
|
||||||
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
|
|
||||||
//{
|
|
||||||
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
|
|
||||||
//{
|
|
||||||
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class MyClass
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -230,7 +53,6 @@ public static class MyClass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class SandboxMain : MonoBehaviour
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
public Button okButton;
|
public Button okButton;
|
||||||
|
@ -239,6 +61,9 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
CancellationTokenSource cts;
|
CancellationTokenSource cts;
|
||||||
|
|
||||||
|
public AsyncReactiveProperty<int> RP1;
|
||||||
|
|
||||||
|
|
||||||
UniTaskCompletionSource ucs;
|
UniTaskCompletionSource ucs;
|
||||||
async UniTask<int> FooAsync()
|
async UniTask<int> FooAsync()
|
||||||
{
|
{
|
||||||
|
@ -300,7 +125,7 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.Full);
|
Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.Full);
|
||||||
Application.SetStackTraceLogType(LogType.Exception, StackTraceLogType.Full);
|
Application.SetStackTraceLogType(LogType.Exception, StackTraceLogType.Full);
|
||||||
|
@ -309,6 +134,13 @@ public class SandboxMain : MonoBehaviour
|
||||||
//ShowPlayerLoop.DumpPlayerLoop("Current", playerLoop);
|
//ShowPlayerLoop.DumpPlayerLoop("Current", playerLoop);
|
||||||
|
|
||||||
|
|
||||||
|
RP1 = new AsyncReactiveProperty<int>(999);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RP1.Select(x => x * x).BindTo(text);
|
||||||
|
|
||||||
|
|
||||||
//Update2().Forget();
|
//Update2().Forget();
|
||||||
|
|
||||||
//RunStandardDelayAsync().Forget();
|
//RunStandardDelayAsync().Forget();
|
||||||
|
@ -342,17 +174,6 @@ public class SandboxMain : MonoBehaviour
|
||||||
// UniTaskAsyncEnumerable.EveryUpdate(PlayerLoopTiming.FixedUpdate)
|
// UniTaskAsyncEnumerable.EveryUpdate(PlayerLoopTiming.FixedUpdate)
|
||||||
|
|
||||||
|
|
||||||
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.Log("Update Trigger 1");
|
|
||||||
}).Forget();
|
|
||||||
|
|
||||||
|
|
||||||
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
|
||||||
{
|
|
||||||
UnityEngine.Debug.Log("Update Trigger 2");
|
|
||||||
}).Forget();
|
|
||||||
|
|
||||||
//await UniTask.Yield(PlayerLoopTiming.Update);
|
//await UniTask.Yield(PlayerLoopTiming.Update);
|
||||||
//Debug.Log("Start:" + Time.frameCount);
|
//Debug.Log("Start:" + Time.frameCount);
|
||||||
|
|
||||||
|
@ -401,8 +222,8 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
|
|
||||||
//await okButton.GetAsyncClickEventHandler().DisableAutoClose()
|
//await okButton.GetAsyncClickEventHandler().DisableAutoClose()
|
||||||
// .Select((_, clickCount) => clickCount + 1)
|
// .Select((_, clickCount) => clickCount + 1)
|
||||||
// .FirstAsync(x => x == 5);
|
// .FirstAsync(x => x == 5);
|
||||||
|
|
||||||
//Debug.Log("Click 5 times.");
|
//Debug.Log("Click 5 times.");
|
||||||
|
|
||||||
|
@ -433,6 +254,9 @@ public class SandboxMain : MonoBehaviour
|
||||||
okButton.onClick.AddListener(() =>
|
okButton.onClick.AddListener(() =>
|
||||||
{
|
{
|
||||||
// FooAsync().Forget();
|
// FooAsync().Forget();
|
||||||
|
|
||||||
|
RP1.Value += 3;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cancelButton.onClick.AddListener(() =>
|
cancelButton.onClick.AddListener(() =>
|
||||||
|
|
Loading…
Reference in New Issue