您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

335 行
9.9 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using RSG;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.async {
public class UIWidgetsCoroutine {
_WaitForSecondsProcessor _waitProcessor;
_WaitForCoroutineProcessor _waitForCoroutine;
_WaitForAsyncOPProcessor _waitForAsyncOPProcessor;
readonly IEnumerator _routine;
readonly Window _window;
readonly IDisposable _unhook;
readonly bool _isBackground;
internal volatile object lastResult;
internal volatile Exception lastError;
internal bool isDone;
readonly Promise<object> _promise = new Promise<object>();
public IPromise<object> promise {
get { return this._promise; }
}
internal UIWidgetsCoroutine(IEnumerator routine, Window window, bool isBackground = false) {
D.assert(routine != null);
D.assert(window != null);
this._routine = routine;
this._window = window;
if (isBackground && BackgroundCallbacks.getInstance() != null) {
this._unhook = BackgroundCallbacks.getInstance().addCallback(this._moveNext);
}
else {
this._unhook = this._window.run(TimeSpan.Zero, this._moveNext, periodic: true);
}
this._isBackground = isBackground;
}
void _moveNext() {
D.assert(!this.isDone);
var lastError = this.lastError;
if (lastError != null) {
this._unhook.Dispose();
this.isDone = true;
this.lastResult = null;
if (this._isBackground) {
this._window.runInMain(() => { this._promise.Reject(lastError); });
}
else {
this._promise.Reject(lastError);
}
return;
}
bool hasNext;
try {
hasNext = this._processIEnumeratorRecursive(this._routine);
}
catch (Exception ex) {
this.stop(ex);
return;
}
if (!hasNext && !this.isDone) {
this._unhook.Dispose();
this.isDone = true;
D.assert(this.lastError == null);
if (this._isBackground) {
this._window.runInMain(() => { this._promise.Resolve(this.lastResult); });
}
else {
this._promise.Resolve(this.lastResult);
}
}
}
bool _processIEnumeratorRecursive(IEnumerator child) {
D.assert(child != null);
if (child.Current is IEnumerator nestedEnumerator) {
return this._processIEnumeratorRecursive(nestedEnumerator) || child.MoveNext();
}
if (child.Current is UIWidgetsCoroutine nestedCoroutine) {
if (this._isBackground) {
throw new Exception("nestedCoroutine is not supported in Background Coroutine");
}
this._waitForCoroutine.set(nestedCoroutine);
return this._waitForCoroutine.moveNext(child, this);
}
if (child.Current is UIWidgetsWaitForSeconds waitForSeconds) {
if (this._isBackground) {
throw new Exception("waitForSeconds is not supported in Background Coroutine");
}
this._waitProcessor.set(waitForSeconds);
return this._waitProcessor.moveNext(child);
}
if (child.Current is AsyncOperation waitForAsyncOP) {
if (this._isBackground) {
throw new Exception("asyncOperation is not supported in Background Coroutine");
}
this._waitForAsyncOPProcessor.set(waitForAsyncOP);
return this._waitForAsyncOPProcessor.moveNext(child);
}
this.lastResult = child.Current;
return child.MoveNext();
}
public void stop() {
this.stop(null);
}
internal void stop(Exception ex) {
if (this.lastError == null) {
this.lastError = ex ?? new CoroutineCanceledException();
}
}
}
struct _WaitForSecondsProcessor {
UIWidgetsWaitForSeconds _current;
float _targetTime;
public void set(UIWidgetsWaitForSeconds yieldStatement) {
if (this._current != yieldStatement) {
this._current = yieldStatement;
this._targetTime = Timer.timeSinceStartup + yieldStatement.waitTime;
}
}
public bool moveNext(IEnumerator enumerator) {
if (this._targetTime <= Timer.timeSinceStartup) {
this._current = null;
this._targetTime = 0;
return enumerator.MoveNext();
}
return true;
}
}
struct _WaitForCoroutineProcessor {
UIWidgetsCoroutine _current;
public void set(UIWidgetsCoroutine routine) {
if (this._current != routine) {
this._current = routine;
}
}
public bool moveNext(IEnumerator enumerator, UIWidgetsCoroutine parent) {
if (this._current.isDone) {
var current = this._current;
this._current = null;
if (current.lastError != null) {
parent.stop(current.lastError);
return false;
}
parent.lastResult = current.lastResult;
return enumerator.MoveNext();
}
return true;
}
}
struct _WaitForAsyncOPProcessor {
AsyncOperation _current;
public void set(AsyncOperation operation) {
if (this._current != operation) {
this._current = operation;
}
}
public bool moveNext(IEnumerator enumerator) {
if (this._current.isDone) {
this._current = null;
return enumerator.MoveNext();
}
return true;
}
}
public static class Coroutine {
public static UIWidgetsCoroutine startCoroutine(this Window owner, IEnumerator routine) {
return new UIWidgetsCoroutine(routine, owner);
}
public static UIWidgetsCoroutine startBackgroundCoroutine(this Window owner, IEnumerator routine) {
return new UIWidgetsCoroutine(routine, owner, isBackground: true);
}
}
public class CoroutineCanceledException : Exception {
}
public class UIWidgetsWaitForSeconds {
public float waitTime { get; }
public UIWidgetsWaitForSeconds(float time) {
this.waitTime = time;
}
}
class BackgroundCallbacks : IDisposable {
static BackgroundCallbacks _instance;
public static BackgroundCallbacks getInstance() {
#if UNITY_WEBGL
return null;
#endif
if (_instance == null) {
_instance = new BackgroundCallbacks(2);
}
return _instance;
}
readonly LinkedList<_CallbackNode> _callbackList;
readonly ManualResetEvent _event;
readonly Thread[] _threads;
volatile bool _aborted = false;
public BackgroundCallbacks(int threadCount = 1) {
this._callbackList = new LinkedList<_CallbackNode>();
this._event = new ManualResetEvent(false);
this._threads = new Thread[threadCount];
for (var i = 0; i < this._threads.Length; i++) {
this._threads[i] = new Thread(this._threadLoop);
this._threads[i].Start();
}
}
public void Dispose() {
foreach (var t in this._threads) {
this._aborted = true;
this._event.Set();
t.Join();
}
this._callbackList.Clear();
}
void _threadLoop() {
while (true) {
if (this._aborted) {
break;
}
LinkedListNode<_CallbackNode> node;
lock (this._callbackList) {
node = this._callbackList.First;
if (node != null) {
this._callbackList.Remove(node);
}
}
if (node == null) {
this._event.WaitOne();
this._event.Reset();
continue;
}
var callbackNode = node.Value;
D.assert(!callbackNode.isDone);
try {
callbackNode.callback();
}
catch (Exception ex) {
D.logError("Failed to execute callback in BackgroundCallbacks: ", ex);
}
if (!callbackNode.isDone) {
lock (this._callbackList) {
this._callbackList.AddLast(node);
}
}
}
}
public IDisposable addCallback(VoidCallback callback) {
var node = new _CallbackNode {callback = callback};
lock (this._callbackList) {
this._callbackList.AddLast(node);
}
this._event.Set();
return new _CallbackDisposable(node);
}
class _CallbackDisposable : IDisposable {
readonly _CallbackNode _node;
public _CallbackDisposable(_CallbackNode node) {
this._node = node;
}
public void Dispose() {
this._node.isDone = true;
}
}
class _CallbackNode {
public VoidCallback callback;
public volatile bool isDone;
}
}
}