Skip to content

Instantly share code, notes, and snippets.

@zsoi
Last active October 25, 2015 17:47
Show Gist options
  • Save zsoi/2de0f2f36fc3f7995786 to your computer and use it in GitHub Desktop.
Save zsoi/2de0f2f36fc3f7995786 to your computer and use it in GitHub Desktop.
Threadsafe Unity3D platform layer ("event loop") for RSG.Promise
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