Last active
October 25, 2018 12:19
-
-
Save paulhayes/da8f4c1daa3f3d3a238f0849046e2400 to your computer and use it in GitHub Desktop.
Concurrent and sequential coroutine helpers. For dual IEnumerators : Sequential, WhileBoth, WhileEither, For n>2 IEnumerators: WhileAny WhileAll Chain. Warning does not work with YieldInstructions
This file contains hidden or 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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace CoroutineUtil | |
{ | |
/* Warning these helper methods can generate plenty of garbage memory, use responsibly */ | |
public class WhileBoth : IEnumerator | |
{ | |
IEnumerator a; | |
IEnumerator b; | |
public WhileBoth (IEnumerator a, IEnumerator b) | |
{ | |
this.a = a; | |
this.b = b; | |
} | |
public object Current { get { return null; } } | |
public bool MoveNext() | |
{ | |
return a.MoveNext() && b.MoveNext(); | |
} | |
public void Reset() {} | |
} | |
public class WhileEither : IEnumerator | |
{ | |
IEnumerator a; | |
IEnumerator b; | |
public WhileEither (IEnumerator a, IEnumerator b) | |
{ | |
this.a = a; | |
this.b = b; | |
} | |
public object Current { get { return null; } } | |
public bool MoveNext() { | |
var aRunning = (a!=null) && a.MoveNext(); | |
var bRunning = (b!=null) && b.MoveNext(); | |
if( aRunning && a.Current is IEnumerator ){ | |
a = new Chain( a.Current as IEnumerator, a ); | |
aRunning = a.MoveNext(); | |
} | |
if( bRunning && b.Current is IEnumerator ){ | |
b = new Chain( b.Current as IEnumerator, b ); | |
bRunning = b.MoveNext(); | |
} | |
return aRunning | bRunning; | |
} | |
public void Reset() {} | |
} | |
public class WhileAny : IEnumerator | |
{ | |
IEnumerator[] routines; | |
public WhileAny (params IEnumerator[] routines) | |
{ | |
this.routines = routines; | |
} | |
public object Current { get { return null; } } | |
public bool MoveNext() { | |
int len = routines.Length; | |
bool isRunning = false; | |
for(int i=0;i<len;i++){ | |
var routine = routines[i]; | |
if( routine == null ) | |
continue; | |
bool hasNext = routine.MoveNext(); | |
isRunning |= hasNext ; | |
if( hasNext && routine.Current is IEnumerator ){ | |
var subRoutine = routine.Current as IEnumerator; | |
if(subRoutine.MoveNext()){ | |
routines[i] = new Sequencial(subRoutine,routine); | |
} | |
} | |
} | |
return isRunning; | |
} | |
public void Reset() {} | |
} | |
public class WhileAll : IEnumerator | |
{ | |
IEnumerator[] routines; | |
public WhileAll (params IEnumerator[] routines) | |
{ | |
this.routines = routines; | |
} | |
public object Current { get { return null; } } | |
public bool MoveNext() { | |
int len = routines.Length; | |
bool isRunning = true; | |
for(int i=0;i<len;i++){ | |
var routine = routines[i]; | |
bool hasNext = routine.MoveNext(); | |
isRunning &= hasNext ; | |
if( hasNext && routine.Current is IEnumerator ){ | |
var subRoutine = routine.Current as IEnumerator; | |
if(subRoutine.MoveNext()){ | |
routines[i] = new Sequencial(subRoutine,routine); | |
} | |
} | |
} | |
return isRunning; | |
} | |
public void Reset() {} | |
} | |
public class Sequencial : IEnumerator | |
{ | |
IEnumerator a; | |
IEnumerator b; | |
public Sequencial (IEnumerator a, IEnumerator b) | |
{ | |
this.a = a; | |
this.b = b; | |
} | |
public object Current { get { return null; } } | |
public bool MoveNext() | |
{ | |
var aRunning = a.MoveNext(); | |
if( aRunning ){ | |
if(a.Current is IEnumerator){ | |
a = new Sequencial(a.Current as IEnumerator,a); | |
aRunning = a.MoveNext(); | |
} | |
} | |
if(!aRunning) { | |
var bRunning = b.MoveNext(); | |
if(bRunning && b.Current is IEnumerator){ | |
b = new Sequencial(b.Current as IEnumerator,b); | |
bRunning = b.MoveNext(); | |
} | |
return bRunning; | |
} | |
return aRunning; | |
} | |
public void Reset() | |
{ | |
} | |
} | |
public class Chain : IEnumerator | |
{ | |
IEnumerator[] chain; | |
int index; | |
public Chain (params IEnumerator[] chain) | |
{ | |
index = 0; | |
this.chain = chain; | |
} | |
public object Current { get { return chain[index].Current; } } | |
public bool MoveNext() | |
{ | |
while( !chain[index].MoveNext() ) { | |
index++; | |
if( index >= chain.Length){ | |
return false; | |
} | |
} | |
return true; | |
} | |
public void Reset() {} | |
} | |
public static class CoroutineUtil | |
{ | |
public static IEnumerator WaitForSeconds(float duration, bool unscaled = false) | |
{ | |
float t = 0; | |
while( t < duration ){ | |
t += unscaled ? Time.unscaledDeltaTime : Time.deltaTime; | |
yield return null; | |
} | |
} | |
public static IEnumerator WrapCustomYield(CustomYieldInstruction custom) | |
{ | |
while(custom.keepWaiting){ | |
yield return null; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment