Last active
October 25, 2015 17:47
-
-
Save zsoi/2de0f2f36fc3f7995786 to your computer and use it in GitHub Desktop.
Threadsafe Unity3D platform layer ("event loop") for RSG.Promise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using namespace RSG; | |
namespace PromisePlatformLayerUnity | |
{ | |
public class UnityPromisePlatformLayer : MonoBehaviour | |
{ | |
static IPromiseTimer gTimer = new ThreadsafePromiseTimer(); | |
// Public access to the promise timer | |
public static IPromiseTimer Timer { get { return gTimer; } } | |
void Update() | |
{ | |
// Pass a tick into the promise timer | |
gTimer.Update(Time.unscaledDeltaTime); | |
} | |
} | |
public class ThreadsafePromiseTimer : IPromiseTimer | |
{ | |
/// <summary> | |
/// The current running total for time that this PromiseTimer has run for | |
/// </summary> | |
private float curTime; | |
/// <summary> | |
/// Currently pending promises | |
/// </summary> | |
private List<PredicateWait> waiting = new List<PredicateWait>(); | |
/// <summary> | |
/// List of promises to add after the current tick | |
/// Access to this list is guarded by a lock so it can be modified by | |
/// multiple threads. | |
/// </summary> | |
private List<PredicateWait> delayedAdded = new List<PredicateWait>(); | |
/// <summary> | |
/// Resolve the returned promise once the time has elapsed | |
/// </summary> | |
public IPromise WaitFor(float seconds) | |
{ | |
return WaitUntil(t => t.elapsedTime >= seconds); | |
} | |
/// <summary> | |
/// Resolve the returned promise once the predicate evaluates to false | |
/// </summary> | |
public IPromise WaitWhile(Func<TimeData, bool> predicate) | |
{ | |
return WaitUntil(t => !predicate(t)); | |
} | |
/// <summary> | |
/// Resolve the returned promise once the predicate evalutes to true | |
/// </summary> | |
public IPromise WaitUntil(Func<TimeData, bool> predicate) | |
{ | |
var promise = new Promise(); | |
var wait = new PredicateWait() | |
{ | |
timeStarted = curTime, | |
pendingPromise = promise, | |
timeData = new TimeData(), | |
predicate = predicate | |
}; | |
// Add to the delayed list, it will later be | |
// merged into the active waiters on the next | |
// update call | |
lock(delayedAdded) | |
{ | |
delayedAdded.Add(wait); | |
} | |
return promise; | |
} | |
/// <summary> | |
/// Update all pending promises. Must be called for the promises to progress and resolve at all. | |
/// </summary> | |
public void Update(float deltaTime) | |
{ | |
curTime += deltaTime; | |
int i = 0; | |
// Add all promises that have been enqueued for addition | |
// to active waiters | |
lock(delayedAdded) | |
{ | |
waiting.AddRange(delayedAdded); | |
delayedAdded.Clear(); | |
} | |
while (i < waiting.Count) | |
{ | |
var wait = waiting[i]; | |
var newElapsedTime = curTime - wait.timeStarted; | |
wait.timeData.deltaTime = newElapsedTime - wait.timeData.elapsedTime; | |
wait.timeData.elapsedTime = newElapsedTime; | |
bool result; | |
try | |
{ | |
result = wait.predicate(wait.timeData); | |
} | |
catch (Exception ex) | |
{ | |
wait.pendingPromise.Reject(ex); | |
waiting.RemoveAt(i); | |
continue; | |
} | |
if (result) | |
{ | |
wait.pendingPromise.Resolve(); | |
waiting.RemoveAt(i); | |
} | |
else | |
{ | |
i++; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment