Skip to content

Commit

Permalink
Fix issue with FSM templates on entities that activate late
Browse files Browse the repository at this point in the history
  • Loading branch information
Extremelyd1 committed Sep 7, 2024
1 parent 31442cf commit 1987de2
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 15 deletions.
62 changes: 51 additions & 11 deletions HKMP/Game/Client/Entity/Entity.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
Expand Down Expand Up @@ -275,6 +276,7 @@ private void ProcessHostFsm(PlayMakerFSM fsm) {

for (var i = 0; i < fsm.FsmStates.Length; i++) {
var state = fsm.FsmStates[i];
var stateName = state.Name;

for (var j = 0; j < state.Actions.Length; j++) {
var action = state.Actions[j];
Expand All @@ -286,18 +288,56 @@ private void ProcessHostFsm(PlayMakerFSM fsm) {
continue;
}

_hookedActions[action] = new HookedEntityAction {
Action = action,
FsmIndex = _fsms.Host.IndexOf(fsm),
StateIndex = i,
ActionIndex = j
};
// Logger.Info($"Created hooked action: {action.GetType()}, {_fsms.Host.IndexOf(fsm)}, {state.Name}, {j}");

if (!_hookedTypes.Contains(action.GetType())) {
_hookedTypes.Add(action.GetType());
Func<FsmStateAction> actionFunc;
var stateIndex = i;
var actionIndex = j;

// Because it can happen that the action from a state is not properly initialized (usually when the
// entity is made active later in the scene and uses an FSM template), we need to check it here
// and create a coroutine that waits for FSM to properly initialize all its states and only then
// continue. When continuing, we no longer use the same instance of the action and state, so we
// use a function that re-obtains the correct action to make a hook from
// This is all complicated logic simply because it happens (empirically) once for the Grimm boss fight
if (action.Fsm == null) {
actionFunc = () => fsm.FsmStates[stateIndex].Actions[actionIndex];
var checkFunc = () => actionFunc.Invoke().Fsm == null;
var sceneName = fsm.gameObject.scene.name;

Logger.Debug($"Registering delayed hook for action that is not valid: {action.GetType()}, {_fsms.Host.IndexOf(fsm)}, {stateName}, {actionIndex}");

MonoBehaviourUtil.Instance.StartCoroutine(WaitForActionInitialization());
IEnumerator WaitForActionInitialization() {
while (checkFunc.Invoke()) {
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != sceneName) {
yield break;
}

yield return new WaitForSeconds(0.1f);
}

Logger.Debug("Delayed hook action is now valid, continuing...");
CreateHookedAction();
}
} else {
actionFunc = () => action;
CreateHookedAction();
}

FsmActionHooks.RegisterFsmStateActionType(action.GetType(), OnActionEntered);
void CreateHookedAction() {
var hookedAction = actionFunc.Invoke();

_hookedActions[hookedAction] = new HookedEntityAction {
Action = hookedAction,
FsmIndex = _fsms.Host.IndexOf(fsm),
StateIndex = stateIndex,
ActionIndex = actionIndex
};
Logger.Info(
$"Created hooked action: {hookedAction.GetType()}, {_fsms.Host.IndexOf(fsm)}, {stateName}, {actionIndex}");

if (_hookedTypes.Add(hookedAction.GetType())) {
FsmActionHooks.RegisterFsmStateActionType(hookedAction.GetType(), OnActionEntered);
}
}
}
}
Expand Down
22 changes: 18 additions & 4 deletions HKMP/Game/Client/Entity/EntityInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,14 @@ public static void InitializeFsm(PlayMakerFSM fsm) {
// Now we can loop over the states in the same order as our "InitStateNames" array
foreach (var state in statesToInit) {
Logger.Debug($"Found initialization state: {state.Name}, executing actions");

// The index of the state in the FSM, NOT in the list of states to initialize
var stateIndex = Array.IndexOf(fsm.FsmStates, state);

// Go over each action and try to execute it by applying empty data to it
foreach (var action in state.Actions) {
for (var actionIndex = 0; actionIndex < state.Actions.Length; actionIndex++) {
var action = state.Actions[actionIndex];

if (!action.Enabled) {
continue;
}
Expand All @@ -93,15 +98,24 @@ public static void InitializeFsm(PlayMakerFSM fsm) {
if (action.Fsm == null) {
Logger.Debug("Initializing FSM and action.Fsm is null, starting coroutine");

var finalActionIndex = actionIndex;
var sceneName = fsm.gameObject.scene.name;
var actionFunc = () => fsm.FsmStates[stateIndex].Actions[finalActionIndex];
var checkFunc = () => actionFunc.Invoke().Fsm == null;

MonoBehaviourUtil.Instance.StartCoroutine(WaitForActionInitialization());
IEnumerator WaitForActionInitialization() {
while (action.Fsm == null) {
while (checkFunc.Invoke()) {
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != sceneName) {
yield break;
}

yield return new WaitForSeconds(0.1f);
}

Logger.Debug("Initializing FSM action completed");
Logger.Debug($"Initializing FSM action completed, executing action: {actionFunc.Invoke().GetType()}");

EntityFsmActions.ApplyNetworkDataFromAction(null, action);
EntityFsmActions.ApplyNetworkDataFromAction(null, actionFunc.Invoke());
}

continue;
Expand Down

0 comments on commit 1987de2

Please sign in to comment.