This code example shows how to protect a unity animation or any long running process from being triggered twice by incoming requests. It handles requests, while the animation is running, gracefully.
Notes:
ReaderWriteLockSlim
is used in favor of lock
or other lock classes, so there is an easy and fast way to check if the animation is runningif (_animationRunning == newState) {
after entering the _lock.EnterWriteLock();
is mandatory and no mistake. There could be a second request that is handed out the write lock before we have aquired it and would result in starting the animation twice.using System.Collections;
using System.Threading;
using RestServer;
using UnityEngine;
public class ExampleAnimation : MonoBehaviour {
private RestServer.RestServer server;
private readonly ReaderWriterLockSlim _lock = new();
private bool _animationRunning;
void Start() {
server.EndpointCollection.RegisterEndpoint(HttpMethod.POST, "/animation/start", request => {
if (IsAnimationRunning()) {
// Quick and save check if the animation is running
request.SendAsyncErrorResponse(423, "Animation is still running");
}
// Start the animation in the main rendering thread
var animationStarted = ThreadingHelper.Instance.ExecuteSync(StartAnimation);
if (animationStarted) {
request.SendAsyncGetResponse("OK");
} else {
request.SendAsyncErrorResponse(423, "Animation is still running");
}
});
}
/// <summary>
/// Start the animation and report the result
/// </summary>
/// <returns>False if animation is still running; true if it was started with this call.</returns>
public bool StartAnimation() {
if (!MarkAnimation(true)) {
// animation already running
return false;
}
// Animation can be started
StartCoroutine(DoAnimation());
return true;
}
private IEnumerator DoAnimation() {
// Animation Step 1
yield return new WaitForSeconds(1.0f);
// Animation Step 2
yield return new WaitForSeconds(1.0f);
// Animation Finished
MarkAnimation(false /* finished */);
yield return null;
}
private bool IsAnimationRunning() {
try {
_lock.EnterReadLock();
return _animationRunning;
}
finally {
_lock.ExitReadLock();
}
}
private bool MarkAnimation(bool newState) {
try {
_lock.EnterWriteLock();
if (_animationRunning == newState) {
return false;
}
_animationRunning = newState;
}
finally {
_lock.ExitWriteLock();
}
return true;
}
}