Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
hfsmbase.c
Go to the documentation of this file.
1 void 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 }
9 void 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 
27 class HFSMBase<Class FSMStateBase, Class FSMEventBase, Class FSMActionBase, Class FSMGuardBase>
28 {
29  protected ref FSMStateBase m_State;
30  protected FSMStateBase m_OwnerState;
31  protected ref FSMStateBase m_InitialState;
33  protected bool m_HasCompletions = false;
34 
35  void HFSMBase (FSMStateBase ownerState = NULL)
36  {
37  m_OwnerState = ownerState;
38  }
39 
43  FSMStateBase GetCurrentState ()
44  {
45  return m_State;
46  }
50  FSMStateBase GetOwnerState ()
51  {
52  return m_OwnerState;
53  }
60  bool GetHierarchyPath (FSMStateBase state, out array<FSMStateBase> path)
61  {
62  FSMStateBase curr = state;
63  while (curr)
64  {
65  path.Insert(curr);
66  curr = curr.GetParentState();
67  }
68  return path.Count() > 0;
69  }
70 
75  void SetInitialState (FSMStateBase initial_state)
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 
97  void Start (FSMEventBase initial_event = NULL, bool useExistingState = false)
98  {
99  if (LogManager.IsInventoryHFSMLogEnable())
100  {
101  fsmDebugPrint("[hfsm] " + this.ToString() + "::Start(" + initial_event.ToString() + "), init_state=" + m_InitialState.ToString());
102  }
103 
104  if (!useExistingState)
105  m_State = m_InitialState;
106 
107  m_State.OnEntry(initial_event);
108 
109  if (m_HasCompletions)
110  ProcessCompletionTransitions();
111  }
115  bool IsRunning () { return m_State != NULL; }
119  void Terminate (FSMEventBase terminal_event = NULL)
120  {
121  if (LogManager.IsInventoryHFSMLogEnable())
122  {
123  fsmDebugPrint("[hfsm] " + this.ToString() + "::Terminate(" + terminal_event.ToString() + ")");
124  }
125 
126  if (IsRunning())
127  {
128  m_State.OnExit(terminal_event);
129  m_State = NULL;
130  }
131  }
132  void Abort (FSMEventBase abort_event = NULL)
133  {
134  if (LogManager.IsInventoryHFSMLogEnable())
135  {
136  fsmDebugPrint("[hfsm] " + this.ToString() + "::Abort(" + abort_event.ToString() + ")");
137  }
138 
139  if (IsRunning())
140  {
141  m_State.OnAbort(abort_event);
142  m_State = NULL;
143  }
144  }
148  void Update (float dt)
149  {
150  if (IsRunning())
151  m_State.OnUpdate(dt);
152  }
153 
154  protected ProcessEventResult ProcessAbortTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
155  {
156  if (LogManager.IsInventoryHFSMLogEnable())
157  {
158  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());
159  }
160 
161  m_State.OnAbort(e); // 1) call onAbort on old state
162 
163  if (t.m_action)
164  t.m_action.Action(e); // 2) execute transition action (if any)
165 
166  auto tmp = t.m_srcState.GetParentState();
167  if (tmp == t.m_dstState.GetParentState())
168  {
169  m_State = t.m_dstState; // 3) change state to new (or NULL)
170 
171  if (t.m_dstState != NULL)
172  {
173  m_State.OnEntry(e); // 4a1) call onEntry on new state (see 4a2) )
174  return ProcessEventResult.FSM_OK;
175  }
176  else
177  {
178  if (LogManager.IsInventoryHFSMLogEnable())
179  {
180  fsmDebugPrint("[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
181  }
182 
183  return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
184  }
185  }
186  else
187  {
188  m_State = NULL;
189  return ProcessEventResult.FSM_ABORTED; // 4c) or signal abort to parent (with appropriate transition)
190  }
191  }
192 
201  FSMStateBase FindAbortDestinationState (FSMEventBase e)
202  {
203  if (LogManager.IsInventoryHFSMLogEnable())
204  {
205  if (GetOwnerState())
206  fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::FindAbortDestinationState(" + e.Type().ToString() + ")");
207  else
208  fsmDebugPrint("[hfsm] root::FindAbortDestinationState(" + e.Type().ToString() + ")");
209  }
210 
211  // 1) look in submachine first (if any)
212  if (m_State && m_State.HasFSM())
213  {
215  FSMStateBase abort_dst = a.FindAbortDestinationState(e);
216 
217  if (abort_dst)
218  {
219  return abort_dst;
220  }
221  }
222 
223  // 2) local transitions
224  int i = FindFirstUnguardedTransition(e);
225  if (i == -1)
226  {
227  if (LogManager.IsInventoryHFSMLogEnable())
228  {
229  fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
230  }
231 
232  return NULL;
233  }
234 
236  return t.m_dstState;
237  }
238 
247  FSMStateBase ProcessAbortEvent(FSMEventBase e, out ProcessEventResult result)
248  {
249  if (LogManager.IsInventoryHFSMLogEnable())
250  {
251  if (GetOwnerState())
252  fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::ProcessAbortEvent(" + e.Type().ToString() + ")");
253  else
254  fsmDebugPrint("[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + ")");
255  }
256 
257  // 1) look in submachine first (if any)
258  if (m_State && m_State.HasFSM())
259  {
261  ProcessEventResult subfsm_res;
262  FSMStateBase abort_dst = a.ProcessAbortEvent(e, subfsm_res);
263 
264  switch (subfsm_res)
265  {
266  case ProcessEventResult.FSM_OK:
267  {
268  if (LogManager.IsInventoryHFSMLogEnable())
269  {
270  fsmDebugPrint("[hfsm] event processed by sub machine=" + m_State.ToString());
271  }
272  result = subfsm_res; // 1.1) submachine accepted event
273  return NULL;
274  }
275  case ProcessEventResult.FSM_ABORTED:
276  {
277  if (LogManager.IsInventoryHFSMLogEnable())
278  {
279  fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString());
280  }
281  m_State.OnAbort(e); // 1.2) submachine aborted, abort submachine owner (i.e. this)
282 
283  if (GetOwnerState() == abort_dst.GetParentState())
284  {
285  if (LogManager.IsInventoryHFSMLogEnable())
286  {
287  fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " & abort destination reached.");
288  }
289  m_State = abort_dst;
290  m_State.OnEntry(e); // 1.3) submachine aborted, call onEntry on new state (cross-hierarchy transition)
291  result = ProcessEventResult.FSM_OK;
292  return NULL;
293  }
294  else
295  {
296  result = ProcessEventResult.FSM_ABORTED; // 1.4) submachine has aborted, look for destination state in parent
297  return NULL;
298  }
299 
300  break;
301  }
302  case ProcessEventResult.FSM_TERMINATED:
303  {
304  break; // submachine has finished, look for local transitions from exited submachine
305  }
306  case ProcessEventResult.FSM_NO_TRANSITION:
307  {
308  if (LogManager.IsInventoryHFSMLogEnable())
309  {
310  fsmDebugPrint("[hfsm] aborted (but no transition) sub machine=" + m_State.ToString());
311  }
312  break; // submachine has no transition, look for transitions in local machine
313  }
314  }
315  }
316 
317  // 2) local transitions
318  int i = FindFirstUnguardedTransition(e);
319  if (i == -1)
320  {
321  if (LogManager.IsInventoryHFSMLogEnable())
322  {
323  fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
324  }
325  result = ProcessEventResult.FSM_NO_TRANSITION;
326  return NULL;
327  }
328 
330  ProcessEventResult res = ProcessAbortTransition(t, e);
331  result = res;
332  switch (res)
333  {
334  case ProcessEventResult.FSM_OK:
335  {
336  //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] abort event processed by machine=" + m_State.ToString());
337  return NULL; // machine accepted event
338  }
339  case ProcessEventResult.FSM_ABORTED:
340  {
341  if (LogManager.IsInventoryHFSMLogEnable())
342  {
343  fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " will fall-through to dst=" + t.m_dstState);
344  }
345  return t.m_dstState; // store destination state for parent(s)
346  }
347 
348  case ProcessEventResult.FSM_TERMINATED:
349  {
350  if (LogManager.IsInventoryHFSMLogEnable())
351  {
352  fsmDebugPrint("[hfsm] aborted & terminated sub machine=" + m_State.ToString());
353  }
354  break; // submachine has finished, look for local transitions from exited submachine
355  }
356  case ProcessEventResult.FSM_NO_TRANSITION:
357  {
358  break; // submachine has no transition, look for transitions in local machine
359  }
360  }
361  return NULL;
362  }
363 
364 
372  ProcessEventResult ProcessEvent(FSMEventBase e)
373  {
374  if (LogManager.IsInventoryHFSMLogEnable())
375  {
376  if (GetOwnerState())
377  fsmDebugPrint("[hfsm] SUB!::" + GetOwnerState().Type().ToString() + "::ProcessEvent(" + e.Type().ToString() + ")");
378  else
379  fsmDebugPrint("[hfsm] root::ProcessEvent(" + e.Type().ToString() + " =" + e.DumpToString());
380  }
381 
382  // 1) completion transitions have priority (if any)
383  if (m_HasCompletions)
384  ProcessCompletionTransitions();
385 
386  // 2) submachine then (if any)
387  if (m_State && m_State.HasFSM())
388  {
389  ProcessEventResult subfsm_res = m_State.ProcessEvent(e);
390 
391  switch (subfsm_res)
392  {
393  case ProcessEventResult.FSM_OK:
394  {
395  if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] event processed by sub machine=" + m_State.ToString());
396  return subfsm_res; // submachine accepted event
397  }
398  case ProcessEventResult.FSM_TERMINATED:
399  {
400  break; // submachine has finished, look for local transitions from exited submachine
401  }
402  case ProcessEventResult.FSM_NO_TRANSITION:
403  {
404  break; // submachine has no transition, look for transitions in local machine
405  }
406  }
407  }
408 
409  // 3) local transitions
410  int i = FindFirstUnguardedTransition(e);
411  if (i == -1)
412  {
413  if (LogManager.IsInventoryHFSMLogEnable())
414  {
415  fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
416  }
417  return ProcessEventResult.FSM_NO_TRANSITION;
418  }
419 
421  ProcessEventResult res;
422  if (row.m_dstState != NULL)
423  {
424  // this is regular transition
425  if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
426  res = LocalTransition(i, e); // transition is within this state machine
427  else
428  Error("cross-hierarchy transition or misconfigured transition detected!");
429  //res = HierarchicTransition(i, e); // transition has to cross hierarchy
430  }
431  else
432  {
433  // this is terminating transition
434  if (row.m_srcState.GetParentState() == GetOwnerState())
435  res = LocalTransition(i, e); // terminating transition is within this state machine
436  else
437  Error("cross-hierarchy transition or misconfigured transition detected!");
438  //res = HierarchicTransition(i, e); // source node crosses hierarchy (terminate lies always within this machine)
439  }
440  return res;
441  }
442 
443  protected int FindFirstUnguardedTransition (FSMEventBase e)
444  {
445  FSMStateBase curr_state = m_State;
446 
447  int count = m_Transitions.Count();
448  for (int i = 0; i < count; ++i)
449  {
451  if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
452  {
453  //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);
454  bool hasGuard = t.m_guard != NULL;
455  if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
456  {
457  return i;
458  }
459  }
460  //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);
461  }
462  return -1;
463  }
464 
465  FSMStateBase FindTransitionState(FSMStateBase s, FSMEventBase e)
466  {
467  FSMStateBase curr_state = s;
468 
469  int count = m_Transitions.Count();
470  for (int i = 0; i < count; ++i)
471  {
473  if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
474  {
475  return t.m_dstState;
476  }
477  }
478  return null;
479  }
480 
481  FSMStateBase FindGuardedTransitionState(FSMStateBase s, FSMEventBase e)
482  {
483  FSMStateBase curr_state = s;
484 
485  int count = m_Transitions.Count();
486  for (int i = 0; i < count; ++i)
487  {
489  if ((t.m_srcState == curr_state) && (t.m_event != NULL) && (t.m_event.Type() == e.Type()))
490  {
491  bool hasGuard = t.m_guard != NULL;
492  if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(e))) // 1) exec guard (if any)
493  {
494  return t.m_dstState;
495  }
496  }
497  }
498  return null;
499  }
500 
501  protected int FindFirstCompletionTransition ()
502  {
503  if (IsRunning())
504  {
505  FSMStateBase curr_state = m_State;
506 
507  int count = m_Transitions.Count();
508  for (int i = 0; i < count; ++i)
509  {
511 
512  //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);
513  if ((t.m_srcState.Type() == curr_state.Type()) && (t.m_event == NULL))
514  {
515  bool hasGuard = t.m_guard != NULL;
516  if (!hasGuard || (hasGuard && t.m_guard.GuardCondition(NULL))) // 1) exec guard (if any)
517  {
518  return i;
519  }
520  }
521  }
522  }
523  return -1;
524  }
525 
526 
533  protected ProcessEventResult ProcessLocalTransition (FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> t, FSMEventBase e)
534  {
535  if (LogManager.IsInventoryHFSMLogEnable())
536  {
537  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());
538  }
539 
540  m_State.OnExit(e); // 1) call onExit on old state
541 
542  if (t.m_action)
543  t.m_action.Action(e); // 2) execute transition action (if any)
544 
545  m_State = t.m_dstState; // 3) change state to new
546 
547  if (t.m_dstState != NULL)
548  {
549  m_State.OnEntry(e); // 4a) call onEntry on new state
550 
551  if (GetOwnerState())
552  GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState); // 5a) notify owner state about change in submachine
553 
554  if (m_State)
555  m_State.OnStateChanged(t.m_srcState, t.m_dstState); // 5b) notify current state about change in machine
556 
557  return ProcessEventResult.FSM_OK;
558  }
559  else
560  {
561  if (LogManager.IsInventoryHFSMLogEnable())
562  {
563  fsmDebugPrint("[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
564  }
565 
566  if (GetOwnerState())
567  GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL); // 5) notify owner state about change in submachine
568  return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
569  }
570  }
577  protected ProcessEventResult LocalTransition (int i, FSMEventBase e)
578  {
580  ProcessEventResult ret = ProcessLocalTransition(t, e);
581  return ret;
582  }
583 
584  protected ProcessEventResult ProcessCompletionTransitions ()
585  {
586  int completionIdx = FindFirstCompletionTransition();
587  while (completionIdx != -1)
588  {
589  FSMTransition<FSMStateBase, FSMEventBase, FSMActionBase, FSMGuardBase> row = m_Transitions.Get(completionIdx);
590  ProcessEventResult res;
591  if (row.m_dstState != NULL)
592  {
593  // this is regular completion transition
594  if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
595  res = LocalTransition(completionIdx, NULL); // transition is within this state machine
596  else
597  Error("cross-hierarchy transition or misconfigured transition detected!");
598  //res = HierarchicTransition(completionIdx, NULL); // transition has to cross hierarchy
599  }
600  else
601  {
602  // this is terminating completion transition
603  if (row.m_srcState.GetParentState() == GetOwnerState())
604  res = LocalTransition(completionIdx, NULL); // terminating transition is within this state machine
605  else
606  Error("cross-hierarchy transition or misconfigured transition detected!");
607  //res = HierarchicTransition(completionIdx, NULL); // source node crosses hierarchy (terminate lies always within this machine)
608  }
609 
610  completionIdx = FindFirstCompletionTransition();
611  }
612  return ProcessEventResult.FSM_NO_TRANSITION;
613  }
614 };
615 
IsRunning
bool IsRunning()
Definition: tools.c:264
Error
void Error(string err)
Messagebox with error message.
Definition: endebug.c:90
HFSMBase
base class for hierarchic finite state machine
LogManager
Definition: debug.c:734
ProcessEvent
void ProcessEvent(EPresenceNotifierNoiseEventType pEventType)
processing of external one-time events (land, fire, etc.)
Definition: pluginpresencenotifier.c:200
Print
proto void Print(void var)
Prints content of variable to console/log.
ToString
proto string ToString()
fsmDebugSpam
void fsmDebugSpam(string s)
Definition: hfsmbase.c:9
PrintToRPT
proto void PrintToRPT(void var)
Prints content of variable to RPT file (performance warning - each write means fflush!...
FSMTransition
represents transition src -— event[guard]/action -—|> dst
array
Result for an object found in CGame.IsBoxCollidingGeometryProxy.
Definition: isboxcollidinggeometryproxyclasses.c:27
Update
proto native volatile void Update()
Definition: playersoundmanager.c:125
Type
string Type
Definition: jsondatacontaminatedarea.c:11
ProcessEventResult
ProcessEventResult
Definition: fsmbase.c:40
fsmDebugPrint
void fsmDebugPrint(string s)
Definition: hfsmbase.c:1
Class
Super root of all classes in Enforce script.
Definition: enscript.c:10
Start
void Start()
Plays all elements this effects consists of.
Definition: effect.c:153
m_State
protected float m_DrainThreshold protected bool m_State
Definition: staminahandler.c:20
path
string path
Definition: optionselectormultistate.c:135