4 class WeaponFSM extends HFSMBase<WeaponStateBase, WeaponEventBase, WeaponActionBase, WeaponGuardBase>
6 private static const int MAX_SYNCHRONIZE_ATTEMPTS = 12;
7 private static const int MIN_SYNCHRONIZE_INTERVAL = 3000;
8 private static const int RESET_SYNCHRONIZE_THRESHOLD = 3600000;
9 private int m_SynchronizeAttempts;
10 private int m_LastSynchronizeTime;
12 protected int m_NextStateId = 0;
17 if (state && state.GetInternalStateID() == -1)
19 state.SetInternalStateID(m_NextStateId);
22 m_UniqueStates.Insert(state);
33 super.AddTransition(t);
35 SetInternalID(t.m_srcState);
36 SetInternalID(t.m_dstState);
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());
48 if (t.m_dstState != NULL)
53 GetOwnerState().OnSubMachineChanged(t.m_srcState, t.m_dstState);
56 m_State.OnStateChanged(t.m_srcState, t.m_dstState);
63 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] terminating fsm: state=" + t.m_srcState.ToString() +
" event=" + e.ToString());
66 GetOwnerState().OnSubMachineChanged(t.m_srcState, NULL);
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());
79 auto tmp = t.m_srcState.GetParentState();
80 if (tmp == t.m_dstState.GetParentState())
84 if (t.m_dstState != NULL)
92 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] abort & terminating fsm: state=" + t.m_srcState.ToString() +
" event=" + e.ToString());
112 fsmDebugPrint(
"[hfsm] root::ProcessAbortEvent(" + e.Type().ToString() +
")");
138 if (GetOwnerState() == abort_dst.GetParentState())
171 int i = FindFirstUnguardedTransition(e);
174 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] abort event has no transition: src=" +
m_State.ToString() +
" e=" + e.Type().ToString());
183 i = FindFirstUnguardedTransition(e);
186 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] abort event has no transition: src=" +
m_State.ToString() +
" e=" + e.Type().ToString());
206 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] aborted sub machine=" +
m_State.ToString() +
" will fall-through to dst=" + t.m_dstState);
233 fsmDebugPrint(
"[hfsm] root::ProcessEvent(" + e.Type().ToString() +
" =" + e.DumpToString());
237 if (m_HasCompletions)
238 ProcessCompletionTransitions();
264 int i = FindFirstUnguardedTransition(e);
267 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] event has no transition: src=" +
m_State.ToString() +
" e=" + e.Type().ToString());
275 i = FindFirstUnguardedTransition(e);
278 if (
LogManager.IsInventoryHFSMLogEnable())
fsmDebugPrint(
"[hfsm] event has no transition: src=" +
m_State.ToString() +
" e=" + e.Type().ToString());
285 if (row.m_dstState != NULL)
288 if (row.m_srcState.GetParentState() == row.m_dstState.GetParentState())
289 res = LocalTransition(i, e);
291 Error(
"cross-hierarchy transition or misconfigured transition detected!");
297 if (row.m_srcState.GetParentState() == GetOwnerState())
298 res = LocalTransition(i, e);
300 Error(
"cross-hierarchy transition or misconfigured transition detected!");
312 int state_count = m_UniqueStates.Count();
313 for (
int idx = 0; idx < state_count; ++idx)
315 int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
317 return m_UniqueStates.Get(idx);
331 int count = m_Transitions.Count();
332 for (
int i = 0; i < count; ++i)
336 if (state &&
id == state.GetCurrentStateID())
344 int curr_state_id = -1;
345 if (!ctx.Read(curr_state_id))
347 Error(
"[wpnfsm] LoadCurrentFSMState - cannot read current state");
355 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] synced current state=" + state +
" id=" + curr_state_id); }
361 Error(
"[wpnfsm] LoadCurrentFSMState - cannot find state for id=" + curr_state_id);
371 if (LoadAndSetCurrentFSMState(ctx, version))
373 bool res =
m_State.LoadCurrentFSMState(ctx, version);
374 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugSpam(
"[wpnfsm] LoadCurrentFSMState - loaded current state=" + GetCurrentState()); }
382 if (LoadAndSetCurrentFSMState(ctx, version))
385 int state_count = m_UniqueStates.Count();
386 for (
int idx = 0; idx < state_count; ++idx)
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));
403 int curr_state_id = state.GetInternalStateID();
404 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] SaveCurrentFSMState - saving current state=" + GetCurrentState() +
" id=" + curr_state_id); }
406 if (!ctx.Write(curr_state_id))
408 Error(
"[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
413 if (!state.SaveCurrentFSMState(ctx))
415 Error(
"[wpnfsm] SaveCurrentFSMState - cannot save currrent state=" +state);
424 int curr_state_id = state.GetInternalStateID();
425 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] SaveCurrentUnstableFSMState - saving current state=" + GetCurrentState() +
" id=" + curr_state_id); }
427 if (!ctx.Write(curr_state_id))
429 Error(
"[wpnfsm] SaveCurrentFSMState - cannot save curr_state_id=" + curr_state_id);
434 int state_count = m_UniqueStates.Count();
435 for (
int idx = 0; idx < state_count; ++idx)
437 int state_id = m_UniqueStates.Get(idx).GetInternalStateID();
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);
445 Error(
"[wpnfsm] SaveCurrentUnstableFSMState state=" + m_UniqueStates.Get(idx) +
" with unassigned ID!");
453 void ValidateAndRepair()
455 Internal_ValidateAndRepair();
462 protected bool Internal_ValidateAndRepair()
464 bool repaired =
false;
468 if (state && state.IsRepairEnabled())
473 repaired |= ValidateAndRepairHelper(weapon,
475 state.HasMagazine(), ( weapon.GetMagazine(0) !=
null ),
476 new WeaponEventAttachMagazine,
new WeaponEventDetachMagazine,
479 repaired |= ValidateAndRepairHelper(weapon,
481 state.IsJammed(), weapon.IsJammed(),
482 new WeaponEventTriggerToJam,
new WeaponEventUnjam,
485 if (weapon.IsJammed())
488 int nMuzzles = weapon.GetMuzzleCount();
493 repaired |= ValidateAndRepairHelper(weapon,
494 "ChamberFiredRepair",
495 state.IsChamberFiredOut(0), weapon.IsChamberFiredOut(0),
496 new WeaponEventTrigger,
new WeaponEventMechanism,
499 repaired |= ValidateAndRepairHelper(weapon,
501 state.IsChamberFull(0), weapon.IsChamberFullEx(0),
502 new WeaponEventLoad1Bullet,
new WeaponEventMechanism,
509 for (
int i = 0; i < nMuzzles; ++i)
511 repaired |= ValidateAndRepairHelper(weapon,
512 "ChamberFiredRepair",
513 state.IsChamberFiredOut(i), weapon.IsChamberFiredOut(i),
517 repaired |= ValidateAndRepairHelper(weapon,
519 state.IsChamberFull(i), weapon.IsChamberFull(i),
535 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] " + weapon.GetDebugName(weapon) +
" ValidateAndRepair - " +
name +
" - " +
m_State +
" - state: " + stateCondition +
" & weapon: " + gunCondition); }
537 if (stateCondition != gunCondition)
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));
549 repairedState = ValidateAndRepairStateFinder(gunCondition, e1, e2, state);
556 state = repairedState;
557 weapon.SyncSelectionState(state.HasBullet(), state.HasMagazine());
558 repairedState.SyncAnimState();
566 if (m_SynchronizeAttempts < MAX_SYNCHRONIZE_ATTEMPTS)
568 int currentTime =
g_Game.GetTime();
569 int timeDiff = currentTime - m_LastSynchronizeTime;
572 if (timeDiff > MIN_SYNCHRONIZE_INTERVAL)
576 if (timeDiff > RESET_SYNCHRONIZE_THRESHOLD)
577 m_SynchronizeAttempts = 0;
582 weapon.RandomizeFSMState();
584 weapon.Synchronize();
586 ++m_SynchronizeAttempts;
587 m_LastSynchronizeTime = currentTime;
592 OnFailThresholdBreached(weapon,
name, stateCondition, gunCondition);
600 protected void OnFailThresholdBreached(
Weapon weapon,
string name,
bool stateCondition,
bool gunCondition)
606 Error(
string.Format(
"[wpnfsm] %1 ValidateAndRepair THRESHOLD BREACH - %2 - %3 - state: %4 != weapon: %5",
607 weapon.GetDebugName(weapon),
name,
m_State, stateCondition, gunCondition));
616 interState = FindTransitionState(state, e1);
618 interState = FindTransitionState(state, e2);
635 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] OnStoreLoad - loading current state=" + state +
" id=" +
id); }
641 Print(
"[wpnfsm] Warning! OnStoreLoad - cannot load curent weapon state, id=" +
id);
657 int GetCurrentStableStateID()
662 return state.GetCurrentStateID();
665 WeaponStateBase abort_dst = FindAbortDestinationState(
new WeaponEventHumanCommandActionAborted(
null));
668 if (closest_stable_state)
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();
674 Print(
"[wpnfsm] Warning! Save occured in fsm transition! GetCurrentStateID - cannot find closest weapon stable state.");
681 int GetInternalStateID()
686 id = curr.GetInternalStateID();
695 int id = GetCurrentStableStateID();
696 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugSpamALot(
"[wpnfsm] OnStoreSave - saving current state=" + GetCurrentState() +
" id=" +
id); }
703 void RandomizeFSMState(
bool hasBullet,
bool hasMagazine,
bool isJammed)
711 RandomizeFSMStateEx(muzzleStates, hasMagazine, isJammed);
719 void RandomizeFSMStateEx(
array<MuzzleState> muzzleStates,
bool hasMagazine,
bool isJammed)
722 int tc = m_Transitions.Count();
726 if (state && state.HasMagazine() == hasMagazine && state.IsJammed() == isJammed)
728 if (state.IsSingleState())
731 candidates.Insert(state);
735 int nMuzzles = muzzleStates.Count();
736 int nMuzzlesState = state.GetMuzzleStateCount();
737 if (nMuzzles != nMuzzlesState)
739 ErrorEx(
string.Format(
"Number of muzzles on the weapon (%1) does not correspond with what state has configured (%2).", nMuzzles, nMuzzlesState));
744 for (
int i = 0; i < nMuzzles; ++i)
746 if (muzzleStates[i] != state.GetMuzzleState(i))
754 candidates.Insert(state);
758 int cc = candidates.Count();
761 int randomIndex =
Math.RandomInt(0, cc);
765 if (!Internal_ValidateAndRepair())
767 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] RandomizeFSMState - randomized current state=" +
m_State +
" id=" + selected.GetCurrentStateID()); }
768 selected.SyncAnimState();
772 if (
LogManager.IsWeaponLogEnable()) {
wpnDebugPrint(
"[wpnfsm] RandomizeFSMState - warning - cannot randomize, no states available"); }