| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- using System.Collections.Generic;
- using System.Diagnostics;
- using System;
- using Urho;
- namespace Urho.Actions
- {
- public class ActionManager : IDisposable
- {
- internal class HashElement
- {
- public int ActionIndex;
- public List<ActionState> ActionStates;
- public ActionState CurrentActionState;
- public bool CurrentActionSalvaged;
- public bool Paused;
- public Node Target;
- }
- static Node[] tmpKeysArray = new Node[128];
- readonly Dictionary<Node, HashElement> targets = new Dictionary<Node, HashElement>();
- bool currentTargetSalvaged;
- HashElement currentTarget;
- bool targetsAvailable = false;
- #region Cleaning up
- ~ActionManager ()
- {
- this.Dispose(false);
- }
- public void Dispose()
- {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- // Dispose of managed resources
- }
- this.RemoveAllActions();
- }
- #endregion Cleaning up
- public BaseAction GetAction(int tag, Node target)
- {
- Debug.Assert(tag != (int)ActionTag.Invalid);
- // Early out if we do not have any targets to search
- if (targets.Count == 0)
- return null;
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- if (element.ActionStates != null)
- {
- int limit = element.ActionStates.Count;
- for (int i = 0; i < limit; i++)
- {
- var action = element.ActionStates[i].Action;
- if (action.Tag == tag)
- {
- return action;
- }
- }
- }
- }
- return null;
- }
- public ActionState GetActionState(int tag, Node target)
- {
- Debug.Assert(tag != (int)ActionTag.Invalid);
- // Early out if we do not have any targets to search
- if (targets.Count == 0)
- return null;
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- if (element.ActionStates != null)
- {
- int limit = element.ActionStates.Count;
- for (int i = 0; i < limit; i++)
- {
- var actionState = element.ActionStates[i];
- if (actionState.Action.Tag == tag)
- {
- return actionState;
- }
- }
- }
- }
- return null;
- }
- public int NumberOfRunningActionsInTarget(Node target)
- {
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- return (element.ActionStates != null) ? element.ActionStates.Count : 0;
- }
- return 0;
- }
- public void Update(float dt)
- {
- if (!targetsAvailable)
- return;
- int count = targets.Count;
- while (tmpKeysArray.Length < count)
- {
- tmpKeysArray = new Node[tmpKeysArray.Length * 2];
- }
- targets.Keys.CopyTo(tmpKeysArray, 0);
- for (int i = 0; i < count; i++)
- {
- HashElement elt;
- if (!targets.TryGetValue(tmpKeysArray[i], out elt))
- {
- continue;
- }
- if (elt.Target.IsDeleted)
- targets.Remove(elt.Target);
- currentTarget = elt;
- currentTargetSalvaged = false;
-
- if (!currentTarget.Paused)
- {
- // The 'actions' may change while inside this loop.
- for (currentTarget.ActionIndex = 0;
- currentTarget.ActionIndex < currentTarget.ActionStates.Count;
- currentTarget.ActionIndex++)
- {
- currentTarget.CurrentActionState = currentTarget.ActionStates[currentTarget.ActionIndex];
- if (currentTarget.CurrentActionState == null)
- {
- continue;
- }
- if (currentTarget.Target.IsDeleted)
- {
- break;
- }
- currentTarget.CurrentActionSalvaged = false;
- currentTarget.CurrentActionState.Step(dt);
- if (currentTarget.CurrentActionSalvaged)
- {
- // The currentAction told the node to remove it. To prevent the action from
- // aidentally deallocating itself before finishing its step, we retained
- // it. Now that step is done, it's safe to release it.
- //currentTarget->currentAction->release();
- }
- else if (currentTarget.CurrentActionState.IsDone)
- {
- currentTarget.CurrentActionState.Stop();
- var actionState = currentTarget.CurrentActionState;
- // Make currentAction nil to prevent removeAction from salvaging it.
- currentTarget.CurrentActionState = null;
- RemoveAction(actionState);
- }
- currentTarget.CurrentActionState = null;
- }
- }
- // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
- if (currentTargetSalvaged && currentTarget.ActionStates.Count == 0)
- {
- DeleteHashElement(currentTarget);
- }
- }
- currentTarget = null;
- }
- internal void DeleteHashElement(HashElement element)
- {
- element.ActionStates.Clear();
- targets.Remove(element.Target);
- element.Target = null;
- targetsAvailable = targets.Count > 0;
- }
- internal void ActionAllocWithHashElement(HashElement element)
- {
- if (element.ActionStates == null)
- {
- element.ActionStates = new List<ActionState>();
- }
- }
- #region Action running
- public void PauseTarget(Node target)
- {
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- element.Paused = true;
- }
- }
- public void ResumeTarget(Node target)
- {
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- element.Paused = false;
- }
- }
- public List<object> PauseAllRunningActions()
- {
- var idsWithActions = new List<object>();
- foreach (var element in targets.Values)
- {
- if (!element.Paused)
- {
- element.Paused = true;
- idsWithActions.Add(element.Target);
- }
- }
- return idsWithActions;
- }
- public void ResumeTargets(List<Node> targetsToResume)
- {
- for (int i = 0; i < targetsToResume.Count; i++)
- {
- ResumeTarget(targetsToResume[i]);
- }
- }
- #endregion Action running
- #region Adding/removing actions
- public ActionState AddAction(BaseAction action, Node target, bool paused = false)
- {
- Debug.Assert(action != null);
- Debug.Assert(target != null);
- HashElement element;
- if (!targets.TryGetValue(target, out element))
- {
- element = new HashElement();
- element.Paused = paused;
- element.Target = target;
- targets.Add(target, element);
- targetsAvailable = true;
- }
- ActionAllocWithHashElement(element);
- var isActionRunning = false;
- foreach (var existingState in element.ActionStates)
- {
- if (existingState.Action == action)
- {
- isActionRunning = true;
- break;
- }
- }
- Debug.Assert(!isActionRunning, "Action is already running for this target.");
- var state = action.StartAction(target);
- element.ActionStates.Add(state);
- return state;
- }
- public void RemoveAllActions()
- {
- if (!targetsAvailable)
- return;
- int count = targets.Count;
- if (tmpKeysArray.Length < count)
- {
- tmpKeysArray = new Node[tmpKeysArray.Length * 2];
- }
- targets.Keys.CopyTo(tmpKeysArray, 0);
- for (int i = 0; i < count; i++)
- {
- RemoveAllActionsFromTarget(tmpKeysArray[i]);
- }
- }
- public void RemoveAllActionsFromTarget(Node target)
- {
- if (target == null)
- {
- return;
- }
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- if (element.ActionStates.Contains(element.CurrentActionState) && (!element.CurrentActionSalvaged))
- {
- element.CurrentActionSalvaged = true;
- }
- element.ActionStates.Clear();
- if (currentTarget == element)
- {
- currentTargetSalvaged = true;
- }
- else
- {
- DeleteHashElement(element);
- }
- }
- }
- public void RemoveAction(ActionState actionState)
- {
- if (actionState == null || actionState.OriginalTarget == null)
- {
- return;
- }
- var target = actionState.OriginalTarget;
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- int i = element.ActionStates.IndexOf(actionState);
- if (i != -1)
- {
- RemoveActionAtIndex(i, element);
- }
- }
- }
- internal void RemoveActionAtIndex(int index, HashElement element)
- {
- var action = element.ActionStates[index];
- if (action == element.CurrentActionState && (!element.CurrentActionSalvaged))
- {
- element.CurrentActionSalvaged = true;
- }
- element.ActionStates.RemoveAt(index);
- // update actionIndex in case we are in tick. looping over the actions
- if (element.ActionIndex >= index)
- {
- element.ActionIndex--;
- }
- if (element.ActionStates.Count == 0)
- {
- if (currentTarget == element)
- {
- currentTargetSalvaged = true;
- }
- else
- {
- DeleteHashElement(element);
- }
- }
- }
- internal void RemoveAction(BaseAction action, Node target)
- {
- if (action == null || target == null)
- return;
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- int limit = element.ActionStates.Count;
- bool actionFound = false;
- for (int i = 0; i < limit; i++)
- {
- var actionState = element.ActionStates[i];
- if (actionState.Action == action && actionState.OriginalTarget == target)
- {
- RemoveActionAtIndex(i, element);
- actionFound = true;
- break;
- }
- }
- }
- }
- public void RemoveAction(int tag, Node target)
- {
- Debug.Assert((tag != (int)ActionTag.Invalid));
- Debug.Assert(target != null);
- // Early out if we do not have any targets to search
- if (targets.Count == 0)
- return;
- HashElement element;
- if (targets.TryGetValue(target, out element))
- {
- int limit = element.ActionStates.Count;
- bool tagFound = false;
- for (int i = 0; i < limit; i++)
- {
- var actionState = element.ActionStates[i];
- if (actionState.Action.Tag == tag && actionState.OriginalTarget == target)
- {
- RemoveActionAtIndex(i, element);
- tagFound = true;
- break;
- }
- }
- }
- }
- #endregion Adding/removing actions
- }
- }
|