Dayz Explorer  1.24.157551 (v105080)
Dayz Code Explorer by Zeroy
weaponfsm.c
Go to the documentation of this file.
1 
4 class WeaponFSM extends HFSMBase<WeaponStateBase, WeaponEventBase, WeaponActionBase, WeaponGuardBase>
5 {
6  private static const int MAX_SYNCHRONIZE_ATTEMPTS = 12;
7  private static const int MIN_SYNCHRONIZE_INTERVAL = 3000; // ms
8  private static const int RESET_SYNCHRONIZE_THRESHOLD = 3600000; // ms
9  private int m_SynchronizeAttempts;
10  private int m_LastSynchronizeTime;
11 
12  protected int m_NextStateId = 0;
13  protected ref array<WeaponStateBase> m_UniqueStates = new array<WeaponStateBase>;
14 
15  protected void SetInternalID(WeaponStateBase state)
16  {
17  if (state && state.GetInternalStateID() == -1)
18  {
19  state.SetInternalStateID(m_NextStateId);
20 
21  //if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] " + Object.GetDebugName(m_weapon) + " unique state=" + state + " has id=" + m_NextStateId); }
22  m_UniqueStates.Insert(state);
23  ++m_NextStateId;
24  }
25  }
26 
32  {
33  super.AddTransition(t);
34 
35  SetInternalID(t.m_srcState);
36  SetInternalID(t.m_dstState);
37  }
38 
40  {
41  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());
42 
43  if (t.m_action)
44  t.m_action.Action(e); // 2) execute transition action (if any)
45 
46  m_State = t.m_dstState; // 3) change state to new
47 
48  if (t.m_dstState != NULL)
49  {
50  m_State.OnEntry(e); // 4a) call onEntry on new state
51 
52  if (GetOwnerState())
53  GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState); // 5a) notify owner state about change in submachine
54 
55  if (m_State)
56  m_State.OnStateChanged(t.m_srcState, t.m_dstState); // 5b) notify current state about change in machine
57 
58  ValidateAndRepair();
59  return ProcessEventResult.FSM_OK;
60  }
61  else
62  {
63  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
64 
65  if (GetOwnerState())
66  GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL); // 5) notify owner state about change in submachine
67  ValidateAndRepair();
68  return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
69  }
70  }
71 
73  {
74  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());
75 
76  if (t.m_action)
77  t.m_action.Action(e); // 2) execute transition action (if any)
78 
79  auto tmp = t.m_srcState.GetParentState();
80  if (tmp == t.m_dstState.GetParentState())
81  {
82  m_State = t.m_dstState; // 3) change state to new (or NULL)
83 
84  if (t.m_dstState != NULL)
85  {
86  m_State.OnEntry(e); // 4a1) call onEntry on new state (see 4a2) )
87  ValidateAndRepair();
88  return ProcessEventResult.FSM_OK;
89  }
90  else
91  {
92  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() + " event=" + e.ToString());
93 
94  return ProcessEventResult.FSM_TERMINATED; // 4b) or terminate
95  }
96  }
97  else
98  {
99  m_State = NULL;
100  ValidateAndRepair();
101  return ProcessEventResult.FSM_ABORTED; // 4c) or signal abort to parent (with appropriate transition)
102  }
103  }
104 
105  override WeaponStateBase ProcessAbortEvent (WeaponEventBase e, out ProcessEventResult result)
106  {
107  if (LogManager.IsInventoryHFSMLogEnable())
108  {
109  if (GetOwnerState())
110  fsmDebugPrint("[hfsm] SUB! " + GetOwnerState().Type().ToString() + "::ProcessAbortEvent(" + e.Type().ToString() + ")");
111  else
112  fsmDebugPrint("[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() + ")");
113  }
114 
115  // 1) look in submachine first (if any)
116  if (m_State && m_State.HasFSM())
117  {
119  ProcessEventResult subfsm_res;
120  WeaponStateBase abort_dst = a.ProcessAbortEvent(e, subfsm_res);
121 
122  switch (subfsm_res)
123  {
124  case ProcessEventResult.FSM_OK:
125  {
126  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] event processed by sub machine=" + m_State.ToString());
127 
128  result = subfsm_res; // 1.1) submachine accepted event
129  ValidateAndRepair();
130  return NULL;
131  }
132  case ProcessEventResult.FSM_ABORTED:
133  {
134  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString());
135 
136  m_State.OnAbort(e); // 1.2) submachine aborted, abort submachine owner (i.e. this)
137 
138  if (GetOwnerState() == abort_dst.GetParentState())
139  {
140  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " & abort destination reached.");
141 
142  m_State = abort_dst;
143  m_State.OnEntry(e); // 1.3) submachine aborted, call onEntry on new state (cross-hierarchy transition)
144  result = ProcessEventResult.FSM_OK;
145  ValidateAndRepair();
146  return NULL;
147  }
148  else
149  {
150  result = ProcessEventResult.FSM_ABORTED; // 1.4) submachine has aborted, look for destination state in parent
151  ValidateAndRepair();
152  return NULL;
153  }
154 
155  break;
156  }
157  case ProcessEventResult.FSM_TERMINATED:
158  {
159  break; // submachine has finished, look for local transitions from exited submachine
160  }
161  case ProcessEventResult.FSM_NO_TRANSITION:
162  {
163  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] aborted (but no transition) sub machine=" + m_State.ToString());
164 
165  break; // submachine has no transition, look for transitions in local machine
166  }
167  }
168  }
169 
170  // 2) local transitions
171  int i = FindFirstUnguardedTransition(e);
172  if (i == -1)
173  {
174  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
175 
176  result = ProcessEventResult.FSM_NO_TRANSITION;
177  ValidateAndRepair();
178  return NULL;
179  }
180 
181  m_State.OnAbort(e);
182 
183  i = FindFirstUnguardedTransition(e);
184  if (i == -1)
185  {
186  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] abort event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
187 
188  result = ProcessEventResult.FSM_NO_TRANSITION;
189  ValidateAndRepair();
190  return NULL;
191  }
192 
194  ProcessEventResult res = ProcessAbortTransition(t, e);
195  result = res;
196  switch (res)
197  {
198  case ProcessEventResult.FSM_OK:
199  {
200  //if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] abort event processed by machine=" + m_State.ToString());
201  ValidateAndRepair();
202  return NULL; // machine accepted event
203  }
204  case ProcessEventResult.FSM_ABORTED:
205  {
206  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] aborted sub machine=" + m_State.ToString() + " will fall-through to dst=" + t.m_dstState);
207 
208  ValidateAndRepair();
209  return t.m_dstState; // store destination state for parent(s)
210  }
211 
212  case ProcessEventResult.FSM_TERMINATED:
213  {
214  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] aborted & terminated sub machine=" + m_State.ToString());
215 
216  break; // submachine has finished, look for local transitions from exited submachine
217  }
218  case ProcessEventResult.FSM_NO_TRANSITION:
219  {
220  break; // submachine has no transition, look for transitions in local machine
221  }
222  }
223  return NULL;
224  }
225 
227  {
228  if (LogManager.IsInventoryHFSMLogEnable())
229  {
230  if (GetOwnerState())
231  fsmDebugPrint("[hfsm] SUB!::" + GetOwnerState().Type().ToString() + "::ProcessEvent(" + e.Type().ToString() + ")");
232  else
233  fsmDebugPrint("[hfsm] root::ProcessEvent(" + e.Type().ToString() + " =" + e.DumpToString());
234  }
235 
236  // 1) completion transitions have priority (if any)
237  if (m_HasCompletions)
238  ProcessCompletionTransitions();
239 
240  // 2) submachine then (if any)
241  if (m_State && m_State.HasFSM())
242  {
243  ProcessEventResult subfsm_res = m_State.ProcessEvent(e);
244 
245  switch (subfsm_res)
246  {
247  case ProcessEventResult.FSM_OK:
248  {
249  if (LogManager.IsWeaponLogEnable()) fsmDebugSpam("[hfsm] event processed by sub machine=" + m_State.ToString());
250  return subfsm_res; // submachine accepted event
251  }
252  case ProcessEventResult.FSM_TERMINATED:
253  {
254  break; // submachine has finished, look for local transitions from exited submachine
255  }
256  case ProcessEventResult.FSM_NO_TRANSITION:
257  {
258  break; // submachine has no transition, look for transitions in local machine
259  }
260  }
261  }
262 
263  // 3) local transitions
264  int i = FindFirstUnguardedTransition(e);
265  if (i == -1)
266  {
267  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
268 
269  return ProcessEventResult.FSM_NO_TRANSITION;
270  }
271 
272  m_State.OnExit(e);
273 
274  // 3.5) find correct transition after handled exit
275  i = FindFirstUnguardedTransition(e);
276  if (i == -1)
277  {
278  if (LogManager.IsInventoryHFSMLogEnable()) fsmDebugPrint("[hfsm] event has no transition: src=" + m_State.ToString() + " e=" + e.Type().ToString());
279 
280  return ProcessEventResult.FSM_NO_TRANSITION;
281  }
282 
284  ProcessEventResult res;
285  if (row.m_dstState != NULL)
286  {
287  // this is regular transition
288  if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
289  res = LocalTransition(i, e); // transition is within this state machine
290  else
291  Error("cross-hierarchy transition or misconfigured transition detected!");
292  //res = HierarchicTransition(i, e); // transition has to cross hierarchy
293  }
294  else
295  {
296  // this is terminating transition
297  if (row.m_srcState.GetParentState() == GetOwnerState())
298  res = LocalTransition(i, e); // terminating transition is within this state machine
299  else
300  Error("cross-hierarchy transition or misconfigured transition detected!");
301  //res = HierarchicTransition(i, e); // source node crosses hierarchy (terminate lies always within this machine)
302  }
303  return res;
304  }
305 
310  WeaponStateBase FindStateForInternalID(int id)
311  {
312  int state_count = m_UniqueStates.Count();
313  for (int idx = 0; idx < state_count; ++idx)
314  {
315  int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
316  if (state_id == id)
317  return m_UniqueStates.Get(idx);
318  }
319  return null;
320  }
321 
326  WeaponStableState FindStableStateForID(int id)
327  {
328  if (id == 0)
329  return null;
330 
331  int count = m_Transitions.Count();
332  for (int i = 0; i < count; ++i)
333  {
334  WeaponTransition trans = m_Transitions.Get(i);
335  WeaponStableState state = WeaponStableState.Cast(trans.m_srcState);
336  if (state && id == state.GetCurrentStateID())
337  return state;
338  }
339  return null;
340  }
341 
342  protected bool LoadAndSetCurrentFSMState(ParamsReadContext ctx, int version)
343  {
344  int curr_state_id = -1;
345  if (!ctx.Read(curr_state_id))
346  {
347  Error("[wpnfsm] LoadCurrentFSMState - cannot read current state");
348  return false;
349  }
350 
351  WeaponStateBase state = FindStateForInternalID(curr_state_id);
352  if (state)
353  {
354  Terminate();
355  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] synced current state=" + state + " id=" + curr_state_id); }
356  m_State = state;
357  Start(null, true);
358  return true;
359  }
360  else
361  Error("[wpnfsm] LoadCurrentFSMState - cannot find state for id=" + curr_state_id);
362  return false;
363 
364  }
365 
369  bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
370  {
371  if (LoadAndSetCurrentFSMState(ctx, version))
372  {
373  bool res = m_State.LoadCurrentFSMState(ctx, version);
374  if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] LoadCurrentFSMState - loaded current state=" + GetCurrentState()); }
375  return res;
376  }
377  return false;
378  }
379 
380  bool LoadCurrentUnstableFSMState(ParamsWriteContext ctx, int version)
381  {
382  if (LoadAndSetCurrentFSMState(ctx, version))
383  {
384  // read all substates
385  int state_count = m_UniqueStates.Count();
386  for (int idx = 0; idx < state_count; ++idx)
387  {
388  if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] LoadCurrentUnstableFSMState " + idx + "/" + state_count + " id=" + m_UniqueStates.Get(idx).GetInternalStateID() + " state=" + m_UniqueStates.Get(idx)); }
389  if (!m_UniqueStates.Get(idx).LoadCurrentFSMState(ctx, version))
390  Error("[wpnfsm] LoadCurrentUnstableFSMState - cannot load unique state " + idx + "/" + state_count + " with id=" + m_UniqueStates.Get(idx).GetInternalStateID() + " state=" + m_UniqueStates.Get(idx));
391  }
392  return true;
393  }
394  return false;
395  }
396 
401  {
402  WeaponStateBase state = GetCurrentState();
403  int curr_state_id = state.GetInternalStateID();
404  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] SaveCurrentFSMState - saving current state=" + GetCurrentState() + " id=" + curr_state_id); }
405 
406  if (!ctx.Write(curr_state_id))
407  {
408  Error("[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
409  return false;
410  }
411 
412  // write only current state
413  if (!state.SaveCurrentFSMState(ctx))
414  {
415  Error("[wpnfsm] SaveCurrentFSMState - cannot save currrent state=" +state);
416  return false;
417  }
418  return true;
419  }
420 
421  bool SaveCurrentUnstableFSMState(ParamsWriteContext ctx)
422  {
423  WeaponStateBase state = GetCurrentState();
424  int curr_state_id = state.GetInternalStateID();
425  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] SaveCurrentUnstableFSMState - saving current state=" + GetCurrentState() + " id=" + curr_state_id); }
426 
427  if (!ctx.Write(curr_state_id))
428  {
429  Error("[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
430  return false;
431  }
432 
433  // write all substates
434  int state_count = m_UniqueStates.Count();
435  for (int idx = 0; idx < state_count; ++idx)
436  {
437  int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
438  if (state_id != -1)
439  {
440  if (LogManager.IsWeaponLogEnable()) { wpnDebugSpam("[wpnfsm] SaveCurrentUnstableFSMState " + idx + "/" + state_count + " id=" + state_id + " name=" + m_UniqueStates.Get(idx)); }
441  if (!m_UniqueStates.Get(idx).SaveCurrentFSMState(ctx))
442  Error("SaveCurrentUnstableFSMState - cannot save unique state=" + m_UniqueStates.Get(idx) + " idx=" + idx + "/" + state_count + " with id=" + state_id);
443  }
444  else
445  Error("[wpnfsm] SaveCurrentUnstableFSMState state=" + m_UniqueStates.Get(idx) + " with unassigned ID!");
446  }
447  return true;
448  }
449 
453  void ValidateAndRepair()
454  {
455  Internal_ValidateAndRepair();
456  }
457 
462  protected bool Internal_ValidateAndRepair()
463  {
464  bool repaired = false;
465 
466  // Only repair stable states
468  if (state && state.IsRepairEnabled())
469  {
470  Weapon_Base weapon = state.m_weapon;
471  if (weapon)
472  {
473  repaired |= ValidateAndRepairHelper(weapon,
474  "MagazineRepair",
475  state.HasMagazine(), ( weapon.GetMagazine(0) != null ),
476  new WeaponEventAttachMagazine, new WeaponEventDetachMagazine,
477  state);
478 
479  repaired |= ValidateAndRepairHelper(weapon,
480  "JammedRepair",
481  state.IsJammed(), weapon.IsJammed(),
482  new WeaponEventTriggerToJam, new WeaponEventUnjam,
483  state);
484 
485  if (weapon.IsJammed())
486  return repaired;
487 
488  int nMuzzles = weapon.GetMuzzleCount();
489  switch (nMuzzles)
490  {
491  case 1:
492  {
493  repaired |= ValidateAndRepairHelper(weapon,
494  "ChamberFiredRepair",
495  state.IsChamberFiredOut(0), weapon.IsChamberFiredOut(0),
496  new WeaponEventTrigger, new WeaponEventMechanism,
497  state);
498 
499  repaired |= ValidateAndRepairHelper(weapon,
500  "ChamberRepair",
501  state.IsChamberFull(0), weapon.IsChamberFullEx(0),
502  new WeaponEventLoad1Bullet, new WeaponEventMechanism,
503  state);
504 
505  break;
506  }
507  default:
508  {
509  for (int i = 0; i < nMuzzles; ++i)
510  {
511  repaired |= ValidateAndRepairHelper(weapon,
512  "ChamberFiredRepair",
513  state.IsChamberFiredOut(i), weapon.IsChamberFiredOut(i),
514  null, null, // A bit brute forced, not really any clean way to transition
515  state);
516 
517  repaired |= ValidateAndRepairHelper(weapon,
518  "ChamberRepair",
519  state.IsChamberFull(i), weapon.IsChamberFull(i),
520  null, null, // A bit brute forced, not really any clean way to transition
521  state);
522  }
523 
524  break;
525  }
526  }
527  }
528  }
529 
530  return repaired;
531  }
532 
533  protected bool ValidateAndRepairHelper(Weapon_Base weapon, string name, bool stateCondition, bool gunCondition, WeaponEventBase e1, WeaponEventBase e2, out WeaponStableState state)
534  {
535  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + weapon.GetDebugName(weapon) + " ValidateAndRepair - " + name + " - " + m_State + " - state: " + stateCondition + " & weapon: " + gunCondition); }
536 
537  if (stateCondition != gunCondition)
538  {
539  WeaponStableState repairedState;
540 
541  // Seeing this message is not TOO bad, it just means this system is working
542  // It is simply being listed in the logs to identify how much the FSM state and weapon state still desyncs
543  // Which can be because of a myriad of causes, such as incorrectly set up transitions
544  // Or simply certain timings of certain actions or interrupts lined up perfectly, which can have repro rates such as 1/300
545  Error(string.Format("[wpnfsm] ValidateAndRepair Attempting to repair: %1 - %2 - %3 - state: %4 != weapon: %5",
546  weapon.GetDebugName(weapon), name, m_State, stateCondition, gunCondition));
547 
548  if (e1 && e2)
549  repairedState = ValidateAndRepairStateFinder(gunCondition, e1, e2, state);
550 
551  if (repairedState)
552  {
553  Terminate();
554  m_State = repairedState;
555  Start(null, true);
556  state = repairedState;
557  weapon.SyncSelectionState(state.HasBullet(), state.HasMagazine());
558  repairedState.SyncAnimState();
559 
560  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] " + weapon.GetDebugName(weapon) + " ValidateAndRepair - " + name + " - Result - " + m_State); }
561  return true;
562  }
563  else
564  {
565  // Last ditch effort
566  if (m_SynchronizeAttempts < MAX_SYNCHRONIZE_ATTEMPTS)
567  {
568  int currentTime = g_Game.GetTime();
569  int timeDiff = currentTime - m_LastSynchronizeTime;
570 
571  // Careful with calling synchronize
572  if (timeDiff > MIN_SYNCHRONIZE_INTERVAL)
573  {
574  // If a lot of time passed since last attempt
575  // There is a possibility the weapon was fixed for a period
576  if (timeDiff > RESET_SYNCHRONIZE_THRESHOLD)
577  m_SynchronizeAttempts = 0;
578 
579  // Only call this on server or in SP
580  // Synchronize will ask the server for its FSM state anyways
581  if (g_Game.IsServer())
582  weapon.RandomizeFSMState();
583 
584  weapon.Synchronize();
585 
586  ++m_SynchronizeAttempts;
587  m_LastSynchronizeTime = currentTime;
588  }
589  }
590  else
591  {
592  OnFailThresholdBreached(weapon, name, stateCondition, gunCondition);
593  }
594  }
595  }
596 
597  return false;
598  }
599 
600  protected void OnFailThresholdBreached(Weapon weapon, string name, bool stateCondition, bool gunCondition)
601  {
602  // Now seeing THIS one, after the one above, THIS one CAN be bad
603  // As the state was identified as being desynced with the actual weapon state
604  // But the system was unable to fix it, so the weapon is now working improperly or not at all
605  // There is even the possibility that this weapon is now permanently broken
606  Error(string.Format("[wpnfsm] %1 ValidateAndRepair THRESHOLD BREACH - %2 - %3 - state: %4 != weapon: %5",
607  weapon.GetDebugName(weapon), name, m_State, stateCondition, gunCondition));
608 
609  // At this point might even consider just deleting the weapon :c
610  }
611 
612  protected WeaponStableState ValidateAndRepairStateFinder(bool condition, WeaponEventBase e1, WeaponEventBase e2, WeaponStableState state)
613  {
614  WeaponStateBase interState;
615  if (condition)
616  interState = FindTransitionState(state, e1);
617  else
618  interState = FindTransitionState(state, e2);
619 
620  WeaponEventBase e = new WeaponEventHumanCommandActionFinished;
621  return WeaponStableState.Cast(FindGuardedTransitionState(interState, e));
622  }
623 
627  bool OnStoreLoad(ParamsReadContext ctx, int version)
628  {
629  int id = 0;
630  ctx.Read(id);
631  WeaponStableState state = FindStableStateForID(id);
632  if (state)
633  {
634  Terminate();
635  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] OnStoreLoad - loading current state=" + state + " id=" + id); }
636  m_State = state;
637  Start(null, true);
638  }
639  else
640  {
641  Print("[wpnfsm] Warning! OnStoreLoad - cannot load curent weapon state, id=" + id);
642  }
643 
644  return true;
645  }
646 
657  int GetCurrentStableStateID()
658  {
659  // 1) if current state is stable state then return ID directly
660  WeaponStableState state = WeaponStableState.Cast(GetCurrentState());
661  if (state)
662  return state.GetCurrentStateID();
663 
664  // 2) otherwise find closest stable state (by looking on abort event)
665  WeaponStateBase abort_dst = FindAbortDestinationState(new WeaponEventHumanCommandActionAborted(null));
666  WeaponStableState closest_stable_state = WeaponStableState.Cast(abort_dst);
667 
668  if (closest_stable_state)
669  {
670  Print("[wpnfsm] Save occured in fsm transition! current state=" + GetCurrentState() + " closes stable state=" + closest_stable_state + " id=" + closest_stable_state.GetCurrentStateID());
671  return closest_stable_state.GetCurrentStateID();
672  }
673 
674  Print("[wpnfsm] Warning! Save occured in fsm transition! GetCurrentStateID - cannot find closest weapon stable state.");
675  return 0;
676  }
677 
681  int GetInternalStateID()
682  {
683  WeaponStateBase curr = GetCurrentState();
684  int id = 0;
685  if (curr)
686  id = curr.GetInternalStateID();
687  return id;
688  }
689 
694  {
695  int id = GetCurrentStableStateID();
696  if (LogManager.IsWeaponLogEnable()) { wpnDebugSpamALot("[wpnfsm] OnStoreSave - saving current state=" + GetCurrentState() + " id=" + id); }
697  ctx.Write(id);
698  }
699 
703  void RandomizeFSMState(bool hasBullet, bool hasMagazine, bool isJammed)
704  {
705  array<MuzzleState> muzzleStates;
706  if (hasBullet)
707  muzzleStates = { MuzzleState.L };
708  else
709  muzzleStates = { MuzzleState.E };
710 
711  RandomizeFSMStateEx(muzzleStates, hasMagazine, isJammed);
712  }
713 
719  void RandomizeFSMStateEx(array<MuzzleState> muzzleStates, bool hasMagazine, bool isJammed)
720  {
722  int tc = m_Transitions.Count();
723  foreach (WeaponTransition trans : m_Transitions)
724  {
725  WeaponStableState state = WeaponStableState.Cast(trans.m_srcState);
726  if (state && state.HasMagazine() == hasMagazine && state.IsJammed() == isJammed)
727  {
728  if (state.IsSingleState())
729  {
730  // There is only one, insert it and stop
731  candidates.Insert(state);
732  break;
733  }
734 
735  int nMuzzles = muzzleStates.Count();
736  int nMuzzlesState = state.GetMuzzleStateCount();
737  if (nMuzzles != nMuzzlesState)
738  {
739  ErrorEx(string.Format("Number of muzzles on the weapon (%1) does not correspond with what state has configured (%2).", nMuzzles, nMuzzlesState));
740  continue;
741  }
742 
743  bool equal = true;
744  for (int i = 0; i < nMuzzles; ++i)
745  {
746  if (muzzleStates[i] != state.GetMuzzleState(i))
747  {
748  equal = false;
749  break;
750  }
751  }
752 
753  if (equal)
754  candidates.Insert(state);
755  }
756  }
757 
758  int cc = candidates.Count();
759  if (cc)
760  {
761  int randomIndex = Math.RandomInt(0, cc);
762  WeaponStableState selected = candidates.Get(randomIndex);
763  Terminate();
764  m_State = selected;
765  if (!Internal_ValidateAndRepair())
766  Start(null, true);
767  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] RandomizeFSMState - randomized current state=" + m_State + " id=" + selected.GetCurrentStateID()); }
768  selected.SyncAnimState();
769  }
770  else
771  {
772  if (LogManager.IsWeaponLogEnable()) { wpnDebugPrint("[wpnfsm] RandomizeFSMState - warning - cannot randomize, no states available"); }
773  }
774  }
775 };
776 
LoadCurrentFSMState
override bool LoadCurrentFSMState(ParamsReadContext ctx, int version)
Definition: weaponchambering.c:867
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
wpnDebugPrint
void wpnDebugPrint(string s)
Definition: debug.c:9
Weapon
script counterpart to engine's class Weapon
Definition: inventoryitem.c:48
Print
proto void Print(void var)
Prints content of variable to console/log.
HFSMBase< WeaponStateBase, WeaponEventBase, WeaponActionBase, WeaponGuardBase >
Definition: weaponfsm.c:4
ToString
proto string ToString()
ErrorEx
enum ShapeType ErrorEx
Serializer
Serialization general interface. Serializer API works with:
Definition: serializer.c:55
fsmDebugSpam
void fsmDebugSpam(string s)
Definition: hfsmbase.c:9
SaveCurrentFSMState
override bool SaveCurrentFSMState(ParamsWriteContext ctx)
Definition: weaponchambering.c:848
wpnDebugSpamALot
void wpnDebugSpamALot(string s)
Definition: debug.c:25
g_Game
DayZGame g_Game
Definition: dayzgame.c:3727
FSMTransition
represents transition src -— event[guard]/action -—|> dst
WeaponTransition
enum FSMTransition WeaponTransition
array< WeaponStateBase >
name
PlayerSpawnPresetDiscreteItemSetSlotData name
one set for cargo
OnStoreSave
void OnStoreSave(ParamsWriteContext ctx)
Definition: modifierbase.c:229
wpnDebugSpam
void wpnDebugSpam(string s)
Definition: debug.c:17
WeaponEventBase
signalize mechanism manipulation
Definition: events.c:34
WeaponStateBase
represent weapon state base
Definition: bullethide.c:1
Weapon_Base
shorthand
Definition: boltactionrifle_base.c:5
Type
string Type
Definition: jsondatacontaminatedarea.c:11
ProcessEventResult
ProcessEventResult
Definition: fsmbase.c:40
fsmDebugPrint
void fsmDebugPrint(string s)
Definition: hfsmbase.c:1
WeaponFSM
weapon finite state machine
Math
Definition: enmath.c:6
Start
void Start()
Plays all elements this effects consists of.
Definition: effect.c:153
OnStoreLoad
bool OnStoreLoad(ParamsReadContext ctx, int version)
Definition: modifiersmanager.c:270
m_State
protected float m_DrainThreshold protected bool m_State
Definition: staminahandler.c:20
WeaponStableState
represents weapon's stable state (i.e. the basic states that the weapon will spend the most time in)
Definition: crossbow.c:26
MuzzleState
MuzzleState
Definition: weaponstablestate.c:14