Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public delegate bool Condition();
- public delegate void Operation();
- namespace Edge
- {
- /// <summary>
- /// The context of each action, it may spawn more sub coroutines.
- /// </summary>
- class ActionContext
- {
- public IEnumerator Action;
- public List<IEnumerator> Spawns;
- public ActionContext(IEnumerator body)
- {
- Action = body;
- Spawns = new List<IEnumerator>();
- }
- }
- /// <summary>
- /// The basic yield instruction of the scheduler system.
- /// </summary>
- public class YieldCommand : IEnumerator
- {
- public virtual object Current
- {
- get { return null; }
- }
- public virtual bool MoveNext()
- {
- return true;
- }
- public virtual void Reset()
- {
- // nop
- }
- }
- /// <summary>
- /// A simple conditional yield instruction of the scheduler system.
- /// </summary>
- public class IfThenYieldCommand : YieldCommand
- {
- public override object Current
- {
- get { return mLock ? this : mBody.Current; }
- }
- public IfThenYieldCommand(Condition cond, IEnumerator body)
- {
- mLock = true;
- mCond = cond;
- mBody = body;
- }
- public override bool MoveNext()
- {
- if (mLock)
- {
- // release the lock if the condition meet
- mLock = !mCond();
- }
- if (!mLock)
- {
- return mBody.MoveNext();
- }
- else
- {
- // always wait
- return true;
- }
- }
- bool mLock = true;
- Condition mCond = null;
- IEnumerator mBody = null;
- }
- /// <summary>
- /// A sequence contains several actions. It allow the nested action and join a certain action dynamically.
- /// </summary>
- public class Flow
- {
- public string UniqueFlowId = string.Empty;
- public Flow(string name)
- {
- UniqueFlowId = name;
- mPendingJobs = new List<IEnumerator>();
- mRequestQuit = false;
- mRequestWait = false;
- mNestedStack = new Stack<ActionContext>();
- }
- public void Stop()
- {
- mRequestQuit = true;
- }
- public void Suspend(bool pause)
- {
- mRequestWait = pause;
- }
- public Flow Join(IEnumerator body)
- {
- if (mNestedStack.Count <= 0)
- {
- // start sequence after the first action is added
- mNestedStack.Push(new ActionContext(body));
- Scheduler.StartUnityCoroutine(SequenceCorountine());
- }
- else
- {
- // put the action to the end of the current action
- Current.Spawns.Add(body);
- }
- return this;
- }
- public Flow Fork(IEnumerator body)
- {
- if (mRequestFork != null)
- {
- Debug.LogError("Cannot fork recursively");
- }
- else
- {
- mRequestFork = body;
- }
- return this;
- }
- ActionContext Current
- {
- get { return mNestedStack.Peek(); }
- }
- IEnumerator SequenceCorountine()
- {
- while (true)
- {
- if (mRequestQuit == true)
- {
- break;
- }
- if (mRequestWait == true)
- {
- yield return null;
- }
- else
- if (!Current.Action.MoveNext())
- {
- // insert all sub-coroutine spawn in the current action orderly
- if (Current.Spawns.Count > 0)
- {
- mPendingJobs.InsertRange(0, Current.Spawns);
- Current.Spawns.Clear();
- }
- // then leave this action
- mNestedStack.Pop();
- // check if we have unfinished actions
- if (mPendingJobs.Count > 0)
- {
- // Debug.Log("Fork into a new sub coroutine.");
- mNestedStack.Push(new ActionContext(mPendingJobs[0]));
- mPendingJobs.RemoveAt(0);
- continue;
- }
- else
- if (mNestedStack.Count > 0)
- {
- continue;
- }
- else
- {
- break; // all action have been done!
- }
- }
- else
- if (mRequestFork != null)
- {
- // prepare to fork
- mNestedStack.Push(new ActionContext(mRequestFork));
- mRequestFork = null;
- continue;
- }
- // some action may wait until some condition meet
- var peek = Current.Action.Current;
- if (peek != Current.Action && peek is IEnumerator)
- {
- //Debug.Log("Fork into a new sub coroutine");
- mNestedStack.Push(new ActionContext(peek as IEnumerator));
- }
- yield return peek;
- }
- }
- IEnumerator mRequestFork = null;
- bool mRequestWait = true;
- bool mRequestQuit = true;
- Stack<ActionContext> mNestedStack = null;
- List<IEnumerator> mPendingJobs = null;
- }
- /// <summary>
- /// Sequence manager, used to append/remove sequence from app.
- /// </summary>
- public class Scheduler : MonoBehaviour
- {
- public static YieldCommand Noop
- {
- get { return noop; }
- }
- static Scheduler self;
- static YieldCommand noop;
- static Scheduler Self()
- {
- if (self == null)
- {
- self = new GameObject("Scheduler").AddComponent<Scheduler>();
- noop = new YieldCommand();
- }
- return self;
- }
- Flow AppendFlow(string name)
- {
- mActiveFlows.Add(new Flow(name));
- return mActiveFlows[mActiveFlows.Count - 1];
- }
- Flow RemoveFlow(string name)
- {
- for(int i = 0; i < mActiveFlows.Count; ++i)
- {
- var flow = mActiveFlows[i];
- if (flow.UniqueFlowId == name)
- {
- flow.Stop();
- mActiveFlows.RemoveAt(i);
- return flow;
- }
- }
- return null;
- }
- public static Flow CreateFlow(string name)
- {
- return Self().AppendFlow(name);
- }
- public static Flow DeleteFlow(string name)
- {
- return Self().RemoveFlow(name);
- }
- public static void StartUnityCoroutine(IEnumerator coroutine)
- {
- Self().StartCoroutine(coroutine);
- }
- public static void Quit()
- {
- Self ().StopAllCoroutines();
- }
- List<Flow> mActiveFlows = new List<Flow>();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement