123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- void fsmDebugPrint (string s)
- {
- #ifdef FSM_DEBUG
- PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
- #else
- //Print("" + s); // comment/uncomment to hide/see debug logs
- #endif
- }
- void fsmDebugSpam (string s)
- {
- #ifdef FSM_DEBUG_SPAM
- PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
- #else
- //Print("" + s); // comment/uncomment to hide/see debug logs
- #endif
- }
- /**@class HFSMBase
- * @brief base class for hierarchic finite state machine
- *
- * stores current state (m_State) and transition table with possible transitions from each state
- * to another state via event
- *
- * each state can have nested state machine, thus creating hierarchy
- **/
- class HFSMBase<Class FSMStateBase, Class FSMEventBase, Class FSMActionBase, Class FSMGuardBase>
- {
- protected ref FSMStateBase m_State; /// current fsm state
- protected FSMStateBase m_OwnerState; /// state that owns this fsm (or null if root)
- protected ref FSMStateBase m_InitialState; /// configurable initial state of the machine
- protected ref array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>> m_Transitions = new array<ref FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase>>; /// fsm transition table
- protected bool m_HasCompletions = false;
- void HFSMBase (FSMStateBase ownerState = NULL)
- {
- m_OwnerState = ownerState;
- }
- /**@fn GetCurrentState
- * @return returns currently active state within this machine (i.e. not hierarchic state)
- **/
- FSMStateBase GetCurrentState ()
- {
- return m_State;
- }
-
- /**@fn SetCurrentState
- * @return returns currently active state within this machine (i.e. not hierarchic state)
- **/
- void SetCurrentState (FSMStateBase state)
- {
- if(m_State != state)
- {
- m_State = state;
- }
- }
- /**@fn GetOwnerState
- * @return returns state that is owner of this fsm submachine. returns null if this is a root machine.
- **/
- FSMStateBase GetOwnerState ()
- {
- return m_OwnerState;
- }
- /**@fn GetHierarchyPath
- * @brief returns hierarchic state (path to root) of a state
- * @param[in] state \p state the path is starting
- * @param[out] path \p current hierarchic state
- * @return true if current state returned in path argument, false otherwise
- **/
- bool GetHierarchyPath (FSMStateBase state, out array<FSMStateBase> path)
- {
- FSMStateBase curr = state;
- while (curr)
- {
- path.Insert(curr);
- curr = curr.GetParentState();
- }
- return path.Count() > 0;
- }
- /**@fn SetInitialState
- * @param[in] initial_state \p state the machine will be entered to after ::Start()
- * @param[in] initial_event \p event that will be used to start the machine
- **/
- void SetInitialState (FSMStateBase initial_state)
- {
- m_InitialState = initial_state;
- }
- /**@fn AddTransition
- * @brief adds transition into transition table
- **/
- void AddTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t)
- {
- m_Transitions.Insert(t);
- //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] +++ ow=" + this.GetOwnerState() + " this=" + this + " t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
- if (t.m_event == NULL)
- {
- Print("Warning (performance): FSM " + this + " has completion transition for src=" + t.m_srcState + " ---NULL----|> dst=" + t.m_dstState);
- m_HasCompletions = true;
- }
- }
- /**@fn Start
- * @brief starts the state machine by entering the initial_state (using intial_event as argument to initial state's onEntry)
- * @param[in] e \p optional event for starting the machind
- **/
- void Start (FSMEventBase initial_event = NULL, bool useExistingState = false)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] " + this.ToString() + "::Start(" + initial_event.ToString() + "), init_state=" + m_InitialState.ToString());
- }
-
- if (!useExistingState)
- m_State = m_InitialState;
-
- m_State.OnEntry(initial_event);
-
- if (m_HasCompletions)
- ProcessCompletionTransitions();
- }
- /**@fn IsRunning
- * @brief returns true if machine is in running state
- **/
- bool IsRunning () { return m_State != NULL; }
- /**@fn Terminate
- * @brief terminates the state machine
- **/
- void Terminate (FSMEventBase terminal_event = NULL)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] " + this.ToString() + "::Terminate(" + terminal_event.ToString() + ")");
- }
-
- if (IsRunning())
- {
- m_State.OnExit(terminal_event);
- m_State = NULL;
- }
- }
- void Abort (FSMEventBase abort_event = NULL)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] " + this.ToString() + "::Abort(" + abort_event.ToString() + ")");
- }
-
- if (IsRunning())
- {
- m_State.OnAbort(abort_event);
- m_State = NULL;
- }
- }
- /**@fn Update
- * @brief if machine running, call OnUpdate() on current state
- **/
- void Update (float dt)
- {
- if (IsRunning())
- m_State.OnUpdate(dt);
- }
- protected ProcessEventResult ProcessAbortTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] (local abort) state=" + t.m_srcState.ToString() + "-------- ABORT event=" + e.ToString() + "[G=" + t.m_guard.ToString() +"]/A=" + t.m_action.ToString() + " --------|> dst=" + t.m_dstState.ToString());
- }
-
- m_State.OnAbort(e); // 1) call onAbort on old state
- if (t.m_action)
- t.m_action.Action(e); // 2) execute transition action (if any)
- auto tmp = t.m_srcState.GetParentState();
- if (tmp == t.m_dstState.GetParentState())
- {
- m_State = t.m_dstState; // 3) change state to new (or NULL)
- if (t.m_dstState != NULL)
- {
- m_State.OnEntry(e); // 4a1) call onEntry on new state (see 4a2) )
- return ProcessEventResult.FSM_OK;
- }
- else
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
- }
-
- return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
- }
- }
- else
- {
- m_State = NULL;
- return ProcessEventResult.FSM_ABORTED; // 4c) or signal abort to parent (with appropriate transition)
- }
- }
- /**@fn FindAbortDestinationState
- * @brief i
- * @param[in] e \p event that will be used to find suitable transition from current state
- * @return FSM_OK if transition found and allowed by guard (if any)
- * @return FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
- * @return FSM_TERMINATED state machine has terminated
- * @return FSM_ABORTED state machine has aborted
- **/
- FSMStateBase FindAbortDestinationState (FSMEventBase e)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- if (GetOwnerState())
- fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::FindAbortDestinationState(" + e.Type().ToString() + ")");
- else
- fsmDebugPrint("[hfsm] root::FindAbortDestinationState(" + e.Type().ToString() + ")");
- }
-
- // 1) look in submachine first (if any)
- if (m_State && m_State.HasFSM())
- {
- HFSMBase<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> a = m_State.GetFSM();
- FSMStateBase abort_dst = a.FindAbortDestinationState(e);
- if (abort_dst)
- {
- return abort_dst;
- }
- }
- // 2) local transitions
- int i = FindFirstUnguardedTransition(e);
- if (i == -1)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
- }
-
- return NULL;
- }
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- return t.m_dstState;
- }
-
- /**@fn ProcessAbortEvent
- * @brief instructs the hierarchical state machine to process the event e
- * @param[in] e \p event that will be used to find suitable transition from current state
- * @return FSM_OK if transition found and allowed by guard (if any)
- * @return FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
- * @return FSM_TERMINATED state machine has terminated
- * @return FSM_ABORTED state machine has aborted
- **/
- FSMStateBase ProcessAbortEvent(FSMEventBase e, out ProcessEventResult result)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- if (GetOwnerState())
- fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::ProcessAbortEvent(" + e.Type().ToString() + ")");
- else
- fsmDebugPrint("[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + ")");
- }
-
- // 1) look in submachine first (if any)
- if (m_State && m_State.HasFSM())
- {
- HFSMBase<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> a = m_State.GetFSM();
- ProcessEventResult subfsm_res;
- FSMStateBase abort_dst = a.ProcessAbortEvent(e, subfsm_res);
- switch (subfsm_res)
- {
- case ProcessEventResult.FSM_OK:
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] event processed by sub machine=" + m_State.ToString());
- }
- result = subfsm_res; // 1.1) submachine accepted event
- return NULL;
- }
- case ProcessEventResult.FSM_ABORTED:
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString());
- }
- m_State.OnAbort(e); // 1.2) submachine aborted, abort submachine owner (i.e. this)
- if (GetOwnerState() == abort_dst.GetParentState())
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " & abort destination reached.");
- }
- m_State = abort_dst;
- m_State.OnEntry(e); // 1.3) submachine aborted, call onEntry on new state (cross-hierarchy transition)
- result = ProcessEventResult.FSM_OK;
- return NULL;
- }
- else
- {
- result = ProcessEventResult.FSM_ABORTED; // 1.4) submachine has aborted, look for destination state in parent
- return NULL;
- }
- break;
- }
- case ProcessEventResult.FSM_TERMINATED:
- {
- break; // submachine has finished, look for local transitions from exited submachine
- }
- case ProcessEventResult.FSM_NO_TRANSITION:
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] aborted (but no transition) sub machine=" + m_State.ToString());
- }
- break; // submachine has no transition, look for transitions in local machine
- }
- }
- }
- // 2) local transitions
- int i = FindFirstUnguardedTransition(e);
- if (i == -1)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
- }
- result = ProcessEventResult.FSM_NO_TRANSITION;
- return NULL;
- }
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- ProcessEventResult res = ProcessAbortTransition(t, e);
- result = res;
- switch (res)
- {
- case ProcessEventResult.FSM_OK:
- {
- //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] abort event processed by machine=" + m_State.ToString());
- return NULL; // machine accepted event
- }
- case ProcessEventResult.FSM_ABORTED:
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " will fall-through to dst=" + t.m_dstState);
- }
- return t.m_dstState; // store destination state for parent(s)
- }
- case ProcessEventResult.FSM_TERMINATED:
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] aborted & terminated sub machine=" + m_State.ToString());
- }
- break; // submachine has finished, look for local transitions from exited submachine
- }
- case ProcessEventResult.FSM_NO_TRANSITION:
- {
- break; // submachine has no transition, look for transitions in local machine
- }
- }
- return NULL;
- }
- /**@fn ProcessEvent
- * @brief instructs the hierarchical state machine to process the event e
- * @param[in] e \p event that will be used to find suitable transition from current state
- * @return FSM_OK if transition found and allowed by guard (if any)
- * @return FSM_NO_TRANSITION if no unguarded transition found in submachine or local machine
- * @return FSM_TERMINATED state machine has terminated
- **/
- ProcessEventResult ProcessEvent(FSMEventBase e)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- if (GetOwnerState())
- fsmDebugPrint("[hfsm] SUB!::" + GetOwnerState().Type().ToString() + "::ProcessEvent(" + e.Type().ToString() + ")");
- else
- fsmDebugPrint("[hfsm] root::ProcessEvent(" + e.Type().ToString() + " =" + e.DumpToString());
- }
-
- // 1) completion transitions have priority (if any)
- if (m_HasCompletions)
- ProcessCompletionTransitions();
- // 2) submachine then (if any)
- if (m_State && m_State.HasFSM())
- {
- ProcessEventResult subfsm_res = m_State.ProcessEvent(e);
- switch (subfsm_res)
- {
- case ProcessEventResult.FSM_OK:
- {
- if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] event processed by sub machine=" + m_State.ToString());
- return subfsm_res; // submachine accepted event
- }
- case ProcessEventResult.FSM_TERMINATED:
- {
- break; // submachine has finished, look for local transitions from exited submachine
- }
- case ProcessEventResult.FSM_NO_TRANSITION:
- {
- break; // submachine has no transition, look for transitions in local machine
- }
- }
- }
- // 3) local transitions
- int i = FindFirstUnguardedTransition(e);
- if (i == -1)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
- }
- return ProcessEventResult.FSM_NO_TRANSITION;
- }
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(i);
- ProcessEventResult res;
- if (row.m_dstState != NULL)
- {
- // this is regular transition
- if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
- res = LocalTransition(i, e); // transition is within this state machine
- else
- Error("cross-hierarchy transition or misconfigured transition detected!");
- //res = HierarchicTransition(i, e); // transition has to cross hierarchy
- }
- else
- {
- // this is terminating transition
- if (row.m_srcState.GetParentState() == GetOwnerState())
- res = LocalTransition(i, e); // terminating transition is within this state machine
- else
- Error("cross-hierarchy transition or misconfigured transition detected!");
- //res = HierarchicTransition(i, e); // source node crosses hierarchy (terminate lies always within this machine)
- }
- return res;
- }
- protected int FindFirstUnguardedTransition (FSMEventBase e)
- {
- FSMStateBase curr_state = m_State;
- int count = m_Transitions.Count();
- for (int i = 0; i < count; ++i)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
- {
- //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] [" + i + "/" + count + "] *** matched! t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
- bool hasGuard = t.m_guard != NULL;
- if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
- {
- return i;
- }
- }
- //else if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm][" + i + "/" + count + "] ... matching t=" + t + " state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
- }
- return -1;
- }
-
- FSMStateBase FindTransitionState(FSMStateBase s, FSMEventBase e)
- {
- FSMStateBase curr_state = s;
- int count = m_Transitions.Count();
- for (int i = 0; i < count; ++i)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
- {
- return t.m_dstState;
- }
- }
- return null;
- }
-
- FSMStateBase FindGuardedTransitionState(FSMStateBase s, FSMEventBase e)
- {
- FSMStateBase curr_state = s;
- int count = m_Transitions.Count();
- for (int i = 0; i < count; ++i)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
- {
- bool hasGuard = t.m_guard != NULL;
- if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
- {
- return t.m_dstState;
- }
- }
- }
- return null;
- }
- protected int FindFirstCompletionTransition ()
- {
- if (IsRunning())
- {
- FSMStateBase curr_state = m_State;
- int count = m_Transitions.Count();
- for (int i = 0; i < count; ++i)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- //if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] (local) matching state=" + t.m_srcState + "-------- event=" + t.m_event + "[G=" + t.m_guard +"]/A=" + t.m_action + " --------|> dst=" + t.m_dstState);
- if ((t.m_srcState.Type() == curr_state.Type()) && (t.m_event == NULL))
- {
- bool hasGuard = t.m_guard != NULL;
- if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(NULL))) // 1) exec guard (if any)
- {
- return i;
- }
- }
- }
- }
- return -1;
- }
- /**@fn ProcessLocalTransition
- * @brief instructs the state machine to process the event locally - no hierarchy is crossed
- * @param[in] t \p the transition in m_Transitions
- * @param[in] e \p event that will be used to process transition from current state
- * @return FSM_OK or FSM_TERMINATED
- **/
- protected ProcessEventResult ProcessLocalTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] (local) state=" + t.m_srcState.ToString() + "-------- event=" + e.ToString() + "[G=" + t.m_guard.ToString() +"]/A=" + t.m_action.ToString() + " --------|> dst=" + t.m_dstState.ToString());
- }
-
- m_State.OnExit(e); // 1) call onExit on old state
- if (t.m_action)
- t.m_action.Action(e); // 2) execute transition action (if any)
- m_State = t.m_dstState; // 3) change state to new
- if (t.m_dstState != NULL)
- {
- m_State.OnEntry(e); // 4a) call onEntry on new state
- if (GetOwnerState())
- GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState); // 5a) notify owner state about change in submachine
-
- if (m_State)
- m_State.OnStateChanged(t.m_srcState, t.m_dstState); // 5b) notify current state about change in machine
- return ProcessEventResult.FSM_OK;
- }
- else
- {
- if (LogManager.IsInventoryHFSMLogEnable())
- {
- fsmDebugPrint("[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
- }
-
- if (GetOwnerState())
- GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL); // 5) notify owner state about change in submachine
- return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
- }
- }
- /**@fn LocalProcessEvent
- * @brief instructs the state machine to process the event e
- * @param[in] i \p index of the transition in m_Transitions
- * @param[in] e \p event that will be used to process transition from current state
- * @return FSM_OK or FSM_TERMINATED
- **/
- protected ProcessEventResult LocalTransition (int i, FSMEventBase e)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- ProcessEventResult ret = ProcessLocalTransition(t, e);
- return ret;
- }
- protected ProcessEventResult ProcessCompletionTransitions ()
- {
- int completionIdx = FindFirstCompletionTransition();
- while (completionIdx != -1)
- {
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(completionIdx);
- ProcessEventResult res;
- if (row.m_dstState != NULL)
- {
- // this is regular completion transition
- if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
- res = LocalTransition(completionIdx, NULL); // transition is within this state machine
- else
- Error("cross-hierarchy transition or misconfigured transition detected!");
- //res = HierarchicTransition(completionIdx, NULL); // transition has to cross hierarchy
- }
- else
- {
- // this is terminating completion transition
- if (row.m_srcState.GetParentState() == GetOwnerState())
- res = LocalTransition(completionIdx, NULL); // terminating transition is within this state machine
- else
- Error("cross-hierarchy transition or misconfigured transition detected!");
- //res = HierarchicTransition(completionIdx, NULL); // source node crosses hierarchy (terminate lies always within this machine)
- }
- completionIdx = FindFirstCompletionTransition();
- }
- return ProcessEventResult.FSM_NO_TRANSITION;
- }
- };
- /** cross-hierarchy transitions (for future use):
- protected bool RemoveCommonParents (out array<WeaponStateBase> src_path, out array<WeaponStateBase> dst_path)
- {
- //for (int j = 0; j < src_path.Count(); ++j) fsmDebugPrint("[hfsm] curr state src_path[" + j + "] = " + src_path[j].ToString());
- //for (int k = 0; k < dst_path.Count(); ++k) fsmDebugPrint("[hfsm] next state dst_path[" + k + "] = " + dst_path[k].ToString());
- while ((src_path.Count() > 0) && (dst_path.Count() > 0) && (src_path.Get(src_path.Count() - 1) == dst_path.Get(dst_path.Count() - 1)))
- {
- src_path.Remove(src_path.Count() - 1);
- dst_path.Remove(dst_path.Count() - 1);
- }
- //for (int je = 0; je < src_path.Count(); ++je) fsmDebugPrint("[hfsm] curr state src_path[" + je + "] = " + src_path[je].ToString());
- //for (int ke = 0; ke < dst_path.Count(); ++ke) fsmDebugPrint("[hfsm] next state dst_path[" + ke + "] = " + dst_path[ke].ToString());
- }
- protected ProcessEventResult HierarchicTransition (int i, FSMEventBase e)
- {
- fsmDebugPrint("[hfsm] { " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ")");
- FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t = m_Transitions.Get(i);
- array<WeaponStateBase> src_path = new array<WeaponStateBase>;
- array<WeaponStateBase> dst_path = new array<WeaponStateBase>;
- if (GetHierarchyPath(t.m_srcState, src_path))
- {
- if (t.m_dstState == NULL)
- {
- Error("cross hierarchy terminate not yet implemented");
- WeaponStateBase curr_state = GetCurrentState();
- //for (int ex = 0; ex < src_path.Count(); ++ex) { fsmDebugPrint("[hfsm] exiting level=" + ex); src_path[ex].OnExit(e); }
- //for (int en = dst_path.Count(); en --> 0;)
- //for (int en = 0; en < dst_path.Count(); ++en) { fsmDebugPrint("[hfsm] entering level=" + en); int ii = dst_path.Count() - 1 - en; dst_path[ii].OnEntry(e); }
- fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> terminated");
- return ProcessEventResult.FSM_TERMINATED;
- }
- else if (GetHierarchyPath(t.m_dstState, dst_path))
- {
- Error("cross hierarchy event implemented, not fully debugged");
- RemoveCommonParents(src_path, dst_path);
- for (int ex = 0; ex < src_path.Count(); ++ex)
- {
- src_path[ex].OnExit(e); // 1) call OnExit on all nodes on src_path ()
- }
- //if (t.m_action)
- // t.m_action.Action(e); // 2) execute transition action (if any)
- //m_State = t.m_dstState; // 4) change state to new
-
- //for (int en = dst_path.Count(); en --> 0;)
- for (int en = 0; en < dst_path.Count(); ++en)
- {
- int ii = dst_path.Count() - 1 - en;
- dst_path[ii].OnEntry(e); // 5) call OnEntry on all nodes on dst_path (@NOTE: reverse order)
- }
- fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> OK");
- return ProcessEventResult.FSM_OK;
- }
- else
- {
- Error("unhandled case, what did you do?");
- }
- }
- fsmDebugPrint("[hfsm] } " + this.ToString() + "::HierarchicTransition(" + e.Type().ToString() + ") --> no transition");
- return ProcessEventResult.FSM_NO_TRANSITION;
- }
- */
|