DayZ 1.24
Loading...
Searching...
No Matches
HFSMBase.c
Go to the documentation of this file.
1void fsmDebugPrint(string s)
2{
3#ifdef FSM_DEBUG
4 PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
5#else
6 //Print("" + s); // comment/uncomment to hide/see debug logs
7#endif
8}
9void fsmDebugSpam(string s)
10{
11#ifdef FSM_DEBUG_SPAM
12 PrintToRPT("" + s); // comment/uncomment to hide/see debug logs
13#else
14 //Print("" + s); // comment/uncomment to hide/see debug logs
15#endif
16}
17
18
28{
33 protected bool m_HasCompletions = false;
34
36 {
37 m_OwnerState = ownerState;
38 }
39
44 {
45 return m_State;
46 }
51 {
52 return m_OwnerState;
53 }
61 {
63 while (curr)
64 {
66 curr = curr.GetParentState();
67 }
68 return path.Count() > 0;
69 }
70
76 {
77 m_InitialState = initial_state;
78 }
83 {
84 m_Transitions.Insert(t);
85 //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);
86 if (t.m_event == NULL)
87 {
88 Print("Warning (performance): FSM " + this + " has completion transition for src=" + t.m_srcState + " ---NULL----|> dst=" + t.m_dstState);
89 m_HasCompletions = true;
90 }
91 }
92
98 {
100 fsmDebugPrint("[hfsm] " + this.ToString() + "::Start(" + initial_event.ToString() + "), init_state=" + m_InitialState.ToString());
101
102 if (!useExistingState)
103 m_State = m_InitialState;
104
105 m_State.OnEntry(initial_event);
106
107 if (m_HasCompletions)
108 ProcessCompletionTransitions();
109 }
113 bool IsRunning() { return m_State != NULL; }
118 {
120 fsmDebugPrint("[hfsm] " + this.ToString() + "::Terminate(" + terminal_event.ToString() + ")");
121
122 if (IsRunning())
123 {
124 m_State.OnExit(terminal_event);
125 m_State = NULL;
126 }
127 }
129 {
131 fsmDebugPrint("[hfsm] " + this.ToString() + "::Abort(" + abort_event.ToString() + ")");
132
133 if (IsRunning())
134 {
135 m_State.OnAbort(abort_event);
136 m_State = NULL;
137 }
138 }
142 void Update(float dt)
143 {
144 if (IsRunning())
145 m_State.OnUpdate(dt);
146 }
147
149 {
151 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());
152
153 m_State.OnAbort(e); // 1) call onAbort on old state
154
155 if (t.m_action)
156 t.m_action.Action(e); // 2) execute transition action (if any)
157
158 auto tmp = t.m_srcState.GetParentState();
159 if (tmp == t.m_dstState.GetParentState())
160 {
161 m_State = t.m_dstState; // 3) change state to new (or NULL)
162
163 if (t.m_dstState != NULL)
164 {
165 m_State.OnEntry(e); // 4a1) call onEntry on new state (see 4a2) )
166 return ProcessEventResult.FSM_OK;
167 }
168 else
169 {
171 fsmDebugPrint("[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
172
173 return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
174 }
175 }
176 else
177 {
178 m_State = NULL;
179 return ProcessEventResult.FSM_ABORTED; // 4c) or signal abort to parent (with appropriate transition)
180 }
181 }
182
192 {
194 {
195 if (GetOwnerState())
196 fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::FindAbortDestinationState(" + e.Type().ToString() + ")");
197 else
198 fsmDebugPrint("[hfsm] root::FindAbortDestinationState(" + e.Type().ToString() + ")");
199 }
200
201 // 1) look in submachine first (if any)
202 if (m_State && m_State.HasFSM())
203 {
205 FSMStateBase abort_dst = a.FindAbortDestinationState(e);
206
207 if (abort_dst)
208 return abort_dst;
209 }
210
211 // 2) local transitions
212 int i = FindFirstUnguardedTransition(e);
213 if (i == -1)
214 {
216 fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
217
218 return NULL;
219 }
220
222 return t.m_dstState;
223 }
224
234 {
236 {
237 if (GetOwnerState())
238 fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::ProcessAbortEvent(" + e.Type().ToString() + ")");
239 else
240 fsmDebugPrint("[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + ")");
241 }
242
243 // 1) look in submachine first (if any)
244 if (m_State && m_State.HasFSM())
245 {
248 FSMStateBase abort_dst = a.ProcessAbortEvent(e, subfsm_res);
249
250 switch (subfsm_res)
251 {
252 case ProcessEventResult.FSM_OK:
253 {
255 fsmDebugPrint("[hfsm] event processed by sub machine=" + m_State.ToString());
256 result = subfsm_res; // 1.1) submachine accepted event
257 return NULL;
258 }
259 case ProcessEventResult.FSM_ABORTED:
260 {
262 fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString());
263 m_State.OnAbort(e); // 1.2) submachine aborted, abort submachine owner (i.e. this)
264
265 if (GetOwnerState() == abort_dst.GetParentState())
266 {
268 fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " & abort destination reached.");
270 m_State.OnEntry(e); // 1.3) submachine aborted, call onEntry on new state (cross-hierarchy transition)
271 result = ProcessEventResult.FSM_OK;
272 return NULL;
273 }
274 else
275 {
276 result = ProcessEventResult.FSM_ABORTED; // 1.4) submachine has aborted, look for destination state in parent
277 return NULL;
278 }
279
280 break;
281 }
282 case ProcessEventResult.FSM_TERMINATED:
283 {
284 break; // submachine has finished, look for local transitions from exited submachine
285 }
286 case ProcessEventResult.FSM_NO_TRANSITION:
287 {
289 fsmDebugPrint("[hfsm] aborted (but no transition) sub machine=" + m_State.ToString());
290 break; // submachine has no transition, look for transitions in local machine
291 }
292 }
293 }
294
295 // 2) local transitions
296 int i = FindFirstUnguardedTransition(e);
297 if (i == -1)
298 {
300 fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
301 result = ProcessEventResult.FSM_NO_TRANSITION;
302 return NULL;
303 }
304
306 ProcessEventResult res = ProcessAbortTransition(t, e);
307 result = res;
308 switch (res)
309 {
310 case ProcessEventResult.FSM_OK:
311 {
312 //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] abort event processed by machine=" + m_State.ToString());
313 return NULL; // machine accepted event
314 }
315 case ProcessEventResult.FSM_ABORTED:
316 {
318 fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " will fall-through to dst=" + t.m_dstState);
319 return t.m_dstState; // store destination state for parent(s)
320 }
321
322 case ProcessEventResult.FSM_TERMINATED:
323 {
325 fsmDebugPrint("[hfsm] aborted & terminated sub machine=" + m_State.ToString());
326 break; // submachine has finished, look for local transitions from exited submachine
327 }
328 case ProcessEventResult.FSM_NO_TRANSITION:
329 {
330 break; // submachine has no transition, look for transitions in local machine
331 }
332 }
333 return NULL;
334 }
335
336
345 {
347 {
348 if (GetOwnerState())
349 fsmDebugPrint("[hfsm] SUB!::" + GetOwnerState().Type().ToString() + "::ProcessEvent(" + e.Type().ToString() + ")");
350 else
351 fsmDebugPrint("[hfsm] root::ProcessEvent(" + e.Type().ToString() + " =" + e.DumpToString());
352 }
353
354 // 1) completion transitions have priority (if any)
355 if (m_HasCompletions)
356 ProcessCompletionTransitions();
357
358 // 2) submachine then (if any)
359 if (m_State && m_State.HasFSM())
360 {
361 ProcessEventResult subfsm_res = m_State.ProcessEvent(e);
362
363 switch (subfsm_res)
364 {
365 case ProcessEventResult.FSM_OK:
366 {
367 if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] event processed by sub machine=" + m_State.ToString());
368 return subfsm_res; // submachine accepted event
369 }
370 case ProcessEventResult.FSM_TERMINATED:
371 {
372 break; // submachine has finished, look for local transitions from exited submachine
373 }
374 case ProcessEventResult.FSM_NO_TRANSITION:
375 {
376 break; // submachine has no transition, look for transitions in local machine
377 }
378 }
379 }
380
381 // 3) local transitions
382 int i = FindFirstUnguardedTransition(e);
383 if (i == -1)
384 {
386 fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
387 return ProcessEventResult.FSM_NO_TRANSITION;
388 }
389
392 if (row.m_dstState != NULL)
393 {
394 // this is regular transition
395 if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
396 res = LocalTransition(i, e); // transition is within this state machine
397 else
398 Error("cross-hierarchy transition or misconfigured transition detected!");
399 //res = HierarchicTransition(i, e); // transition has to cross hierarchy
400 }
401 else
402 {
403 // this is terminating transition
404 if (row.m_srcState.GetParentState() == GetOwnerState())
405 res = LocalTransition(i, e); // terminating transition is within this state machine
406 else
407 Error("cross-hierarchy transition or misconfigured transition detected!");
408 //res = HierarchicTransition(i, e); // source node crosses hierarchy (terminate lies always within this machine)
409 }
410 return res;
411 }
412
414 {
416
417 int count = m_Transitions.Count();
418 for (int i = 0; i < count; ++i)
419 {
421 if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
422 {
423 //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);
424 bool hasGuard = t.m_guard != NULL;
425 if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
426 return i;
427 }
428 //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);
429 }
430 return -1;
431 }
432
434 {
436
437 int count = m_Transitions.Count();
438 for (int i = 0; i < count; ++i)
439 {
441 if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
442 return t.m_dstState;
443 }
444 return null;
445 }
446
448 {
450
451 int count = m_Transitions.Count();
452 for (int i = 0; i < count; ++i)
453 {
455 if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
456 {
457 bool hasGuard = t.m_guard != NULL;
458 if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
459 return t.m_dstState;
460 }
461 }
462 return null;
463 }
464
466 {
467 if (IsRunning())
468 {
470
471 int count = m_Transitions.Count();
472 for (int i = 0; i < count; ++i)
473 {
475
476 //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);
477 if ((t.m_srcState.Type() == curr_state.Type()) && (t.m_event == NULL))
478 {
479 bool hasGuard = t.m_guard != NULL;
480 if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(NULL))) // 1) exec guard (if any)
481 return i;
482 }
483 }
484 }
485 return -1;
486 }
487
488
496 {
498 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());
499
500 m_State.OnExit(e); // 1) call onExit on old state
501
502 if (t.m_action)
503 t.m_action.Action(e); // 2) execute transition action (if any)
504
505 m_State = t.m_dstState; // 3) change state to new
506
507 if (t.m_dstState != NULL)
508 {
509 m_State.OnEntry(e); // 4a) call onEntry on new state
510
511 if (GetOwnerState())
512 GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState); // 5a) notify owner state about change in submachine
513
514 if (m_State)
515 m_State.OnStateChanged(t.m_srcState, t.m_dstState); // 5b) notify current state about change in machine
516
517 return ProcessEventResult.FSM_OK;
518 }
519 else
520 {
522 fsmDebugPrint("[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
523
524 if (GetOwnerState())
525 GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL); // 5) notify owner state about change in submachine
526 return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
527 }
528 }
536 {
538 ProcessEventResult ret = ProcessLocalTransition(t, e);
539 return ret;
540 }
541
543 {
544 int completionIdx = FindFirstCompletionTransition();
545 while (completionIdx != -1)
546 {
549 if (row.m_dstState != NULL)
550 {
551 // this is regular completion transition
552 if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
553 res = LocalTransition(completionIdx, NULL); // transition is within this state machine
554 else
555 Error("cross-hierarchy transition or misconfigured transition detected!");
556 //res = HierarchicTransition(completionIdx, NULL); // transition has to cross hierarchy
557 }
558 else
559 {
560 // this is terminating completion transition
561 if (row.m_srcState.GetParentState() == GetOwnerState())
562 res = LocalTransition(completionIdx, NULL); // terminating transition is within this state machine
563 else
564 Error("cross-hierarchy transition or misconfigured transition detected!");
565 //res = HierarchicTransition(completionIdx, NULL); // source node crosses hierarchy (terminate lies always within this machine)
566 }
567
568 completionIdx = FindFirstCompletionTransition();
569 }
570 return ProcessEventResult.FSM_NO_TRANSITION;
571 }
572};
573
proto string ToString()
ProcessEventResult
Definition FSMBase.c:41
void fsmDebugSpam(string s)
Definition HFSMBase.c:9
void fsmDebugPrint(string s)
Definition HFSMBase.c:1
string Type
bool m_State
Super root of all classes in Enforce script.
Definition EnScript.c:11
void AddTransition(FSMTransition< FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase > t)
adds transition into transition table
Definition HFSMBase.c:82
ProcessEventResult ProcessAbortTransition(FSMTransition< FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase > t, FSMEventBase e)
Definition HFSMBase.c:148
bool GetHierarchyPath(FSMStateBase state, out array< FSMStateBase > path)
returns hierarchic state (path to root) of a state
Definition HFSMBase.c:60
ref FSMStateBase m_InitialState
state that owns this fsm (or null if root)
Definition HFSMBase.c:31
void Update(float dt)
if machine running, call OnUpdate() on current state
Definition HFSMBase.c:142
void Terminate(FSMEventBase terminal_event=NULL)
terminates the state machine
Definition HFSMBase.c:117
void Start(FSMEventBase initial_event=NULL, bool useExistingState=false)
starts the state machine by entering the initial_state (using intial_event as argument to initial sta...
Definition HFSMBase.c:97
FSMStateBase ProcessAbortEvent(FSMEventBase e, out ProcessEventResult result)
instructs the hierarchical state machine to process the event e
Definition HFSMBase.c:233
ProcessEventResult ProcessEvent(FSMEventBase e)
instructs the hierarchical state machine to process the event e
Definition HFSMBase.c:344
ProcessEventResult ProcessLocalTransition(FSMTransition< FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase > t, FSMEventBase e)
instructs the state machine to process the event locally - no hierarchy is crossed
Definition HFSMBase.c:495
base class for hierarchic finite state machine
static bool IsWeaponLogEnable()
Definition Debug.c:799
static bool IsInventoryHFSMLogEnable()
Definition Debug.c:749
string ToString()
Definition EnConvert.c:3
void Error(string err)
Messagebox with error message.
Definition EnDebug.c:90
proto void Print(void var)
Prints content of variable to console/log.
proto void PrintToRPT(void var)
Prints content of variable to RPT file (performance warning - each write means fflush!...
proto void Insert(int index, string input)
Inserts a string into the n-th index, increasing the string length by the size of the input.
bool IsRunning()
Definition tools.c:252