Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FsmMaster v0.2.7
plugins/FsmMaster.dll
Decompiled 3 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DebugMod; using DebugMod.SaveStates; using HarmonyLib; using HutongGames.PlayMaker; using InControl; using Microsoft.CodeAnalysis; using Silksong.FsmUtil; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("FsmMaster")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.7.0")] [assembly: AssemblyInformationalVersion("0.2.7+db1c73b7555f357914b93cf3353e622ac4772f86")] [assembly: AssemblyProduct("FsmMaster")] [assembly: AssemblyTitle("FsmMaster")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ConstructiveCynicism/FsmMaster")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.7.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace FsmMaster { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("org.silksong-modding.modlist", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("io.github.constructivecynicism.fsmmaster", "FsmMaster", "0.2.7")] public class FsmMasterPlugin : BaseUnityPlugin { private FsmEditManager? _editManager; private DebugModCompat? _debugModCompat; private FsmVariableTracker? _variableTracker; private FsmTabManager? _tabManager; private FsmGraphOverlay? _graphOverlay; private UICommon? _uiCommon; private GameObject? _canvasGameObject; private bool _ownsEventSystem; private FsmRightPanel? _rightPanel; private FsmMonitorPanel? _monitorPanel; private FsmPanelLayoutConfig? _rightPanelLayout; private FsmPanelLayoutConfig? _monitorPanelLayout; private ConfigEntry<bool>? _autoLoadConfig; private ConfigFile? _uiStateConfig; private readonly List<CanvasNode> _rightPanelSubtreeBuffer = new List<CanvasNode>(); private readonly List<CanvasNode> _monitorPanelSubtreeBuffer = new List<CanvasNode>(); private int _rightPanelSubtreeVersion = -1; private int _monitorPanelSubtreeVersion = -1; private static Harmony? _harmony; public const string Id = "io.github.constructivecynicism.fsmmaster"; internal static FsmEditManager? ActiveEditManagerForPatches { get; private set; } internal static bool ForceCursorVisible { get; private set; } internal FsmVariableTracker? VariableTracker => _variableTracker; public static string Name => "FsmMaster"; public static string Version => "0.2.7"; private void Awake() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.constructivecynicism.fsmmaster) has loaded!")); _harmony = Harmony.CreateAndPatchAll(typeof(FsmMasterPlugin).Assembly, (string)null); ConfigEntry<KeyboardShortcut> val = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Toggle Overlay", new KeyboardShortcut((KeyCode)284, Array.Empty<KeyCode>()), "Shows or hides the FSM graph overlay and its right-side panel."); ConfigEntry<KeyboardShortcut> toggleMinimalViewHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "Toggle Minimal View", KeyboardShortcut.Empty, "While the overlay is visible, switches between the full selection UI and a minimal graph-only view. Unbound by default."); FsmGraphColorConfig colors = FsmGraphColorConfig.Bind(((BaseUnityPlugin)this).Config); FsmGraphPerformanceConfig performance = FsmGraphPerformanceConfig.Bind(((BaseUnityPlugin)this).Config); _autoLoadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Auto Load Last Configuration", true, "When enabled, each FSM's most recently saved/loaded named configuration is automatically reapplied whenever a scene containing that FSM loads. Toggled in-game by the panel's Auto button."); Directory.CreateDirectory(FsmSaveDataStore.DataDirectory); _uiStateConfig = new ConfigFile(Path.Combine(FsmSaveDataStore.DataDirectory, "io.github.constructivecynicism.fsmmaster.UIState.cfg"), false); _rightPanelLayout = FsmPanelLayoutConfig.Bind(_uiStateConfig, "FsmMaster Panel"); _monitorPanelLayout = FsmPanelLayoutConfig.Bind(_uiStateConfig, "Monitor Panel"); ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { Browsable = false }; ConfigEntry<bool> val2 = _uiStateConfig.Bind<bool>("General", "First Run Complete", false, new ConfigDescription("Set automatically once the mod has shown its first-run hotkey hint. Not meant to be hand-edited.", (AcceptableValueBase)null, new object[1] { configurationManagerAttributes })); bool flag = !val2.Value; _editManager = new FsmEditManager(((BaseUnityPlugin)this).Logger); ActiveEditManagerForPatches = _editManager; _debugModCompat = DebugModCompat.TryCreate(_editManager, RescanLiveFsmsForDebugModLoad, ((BaseUnityPlugin)this).Logger); _variableTracker = new FsmVariableTracker((string fsmKey) => _editManager.GetLiveInstances(fsmKey)); _tabManager = new FsmTabManager(); _graphOverlay = new FsmGraphOverlay(((BaseUnityPlugin)this).Logger, _editManager, _tabManager, val, toggleMinimalViewHotkey, colors, performance, flag); Scene activeScene = SceneManager.GetActiveScene(); string sceneName = ((Scene)(ref activeScene)).name ?? string.Empty; PlayMakerFSM[] components = Object.FindObjectsByType<PlayMakerFSM>((FindObjectsInactive)1, (FindObjectsSortMode)0); Dictionary<string, List<PlayMakerFSM>> groupsByFsmKey = ApplyPersistedEditsForScene(sceneName, components); _graphOverlay.RefreshSnapshot(sceneName, components); _tabManager.RebindAfterRefresh(groupsByFsmKey); BuildRightPanel(); if (flag) { _rightPanel.ShowStatus($"{val.Value} to toggle UI", _uiCommon.AccentColor, 12f); val2.Value = true; } SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; _debugModCompat?.Unhook(); _debugModCompat = null; _editManager?.RevertAllForUnload(); _editManager = null; ActiveEditManagerForPatches = null; _variableTracker = null; _tabManager = null; _graphOverlay?.Shutdown(); _graphOverlay = null; ForceCursorVisible = false; DestroyRightPanel(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; _uiStateConfig = null; } private void Update() { _editManager?.PollPendingActivations(); _graphOverlay?.Update(); ForceCursorVisible = _graphOverlay?.IsVisible ?? false; if (_rightPanel != null) { _rightPanel.ActiveSelf = _graphOverlay != null && _graphOverlay.IsVisible && _graphOverlay.SelectionUiVisible; FsmTabState fsmTabState = _tabManager?.GetActive(); FsmInfo fsm = ((fsmTabState == null || !fsmTabState.IsLive) ? null : _graphOverlay?.ResolveFsmInfo(fsmTabState.FsmKey)); _rightPanel.ActiveStatePanel.Refresh(fsm, fsmTabState?.SelectedStateName, fsmTabState?.FsmKey); int? num = fsmTabState?.PendingScrollActionIndex; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); _rightPanel.ActiveStatePanel.ScrollToAction(valueOrDefault); fsmTabState.PendingScrollActionIndex = null; } _rightPanel.ActiveStatePanel.RefreshLiveValues(); if (_rightPanelSubtreeVersion != CanvasPanel.StructureVersion) { _rightPanelSubtreeBuffer.Clear(); _rightPanel.CollectSubtree(_rightPanelSubtreeBuffer); _rightPanelSubtreeVersion = CanvasPanel.StructureVersion; } foreach (CanvasNode item in _rightPanelSubtreeBuffer) { if (item.ActiveInHierarchy) { item.Update(); } } } if (_monitorPanel == null) { return; } _monitorPanel.ActiveSelf = _graphOverlay != null && _graphOverlay.IsVisible; _monitorPanel.Locked = _graphOverlay != null && !_graphOverlay.SelectionUiVisible; _monitorPanel.RefreshRows(_variableTracker); if (_monitorPanelSubtreeVersion != CanvasPanel.StructureVersion) { _monitorPanelSubtreeBuffer.Clear(); _monitorPanel.CollectSubtree(_monitorPanelSubtreeBuffer); _monitorPanelSubtreeVersion = CanvasPanel.StructureVersion; } foreach (CanvasNode item2 in _monitorPanelSubtreeBuffer) { if (item2.ActiveInHierarchy) { item2.Update(); } } } private void OnGUI() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Rect? rightPanelScreenRect = null; FsmRightPanel rightPanel = _rightPanel; if (rightPanel != null && rightPanel.ActiveInHierarchy) { rightPanelScreenRect = new Rect(_rightPanel.Position.x, _rightPanel.Position.y, _rightPanel.Size.x, _rightPanel.Size.y); } Rect? monitorPanelScreenRect = null; FsmMonitorPanel monitorPanel = _monitorPanel; if (monitorPanel != null && monitorPanel.ActiveInHierarchy) { monitorPanelScreenRect = new Rect(_monitorPanel.Position.x, _monitorPanel.Position.y, _monitorPanel.Size.x, _monitorPanel.Size.y); } Rect? openDropdownScreenRect = _rightPanel?.OpenDropdownScreenRect; _graphOverlay?.OnGUI(_tabManager?.GetActive(), rightPanelScreenRect, monitorPanelScreenRect, openDropdownScreenRect); } private void BuildRightPanel() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Object.FindFirstObjectByType<EventSystem>() == (Object)null) { GameObject val = new GameObject("FsmMasterEventSystem"); val.AddComponent<EventSystem>(); val.AddComponent<StandaloneInputModule>(); _ownsEventSystem = true; } _canvasGameObject = new GameObject("FsmMasterCanvas"); _canvasGameObject.transform.SetParent(((Component)this).transform, false); _canvasGameObject.AddComponent<Canvas>().renderMode = (RenderMode)0; _canvasGameObject.AddComponent<GraphicRaycaster>(); _uiCommon = new UICommon(); _rightPanel = new FsmRightPanel(_uiCommon, _tabManager, _editManager, _variableTracker, () => _graphOverlay?.CurrentSnapshot, () => _graphOverlay?.GraphVisible ?? true, delegate(bool visible) { if (_graphOverlay != null) { _graphOverlay.GraphVisible = visible; } }, ((BaseUnityPlugin)this).Logger, _rightPanelLayout, _autoLoadConfig); _rightPanel.Build(_canvasGameObject.transform); _monitorPanel = new FsmMonitorPanel(_uiCommon, _variableTracker, _monitorPanelLayout); _monitorPanel.Build(_canvasGameObject.transform); } private void DestroyRightPanel() { _rightPanel?.Destroy(); _rightPanel = null; _monitorPanel?.Destroy(); _monitorPanel = null; if ((Object)(object)_canvasGameObject != (Object)null) { Object.Destroy((Object)(object)_canvasGameObject); _canvasGameObject = null; } if (_ownsEventSystem) { EventSystem val = Object.FindFirstObjectByType<EventSystem>(); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } _ownsEventSystem = false; } _uiCommon?.Destroy(); _uiCommon = null; } internal void RescanLiveFsmsForDebugModLoad() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); string sceneName = ((Scene)(ref activeScene)).name ?? string.Empty; PlayMakerFSM[] components = Object.FindObjectsByType<PlayMakerFSM>((FindObjectsInactive)1, (FindObjectsSortMode)0); Dictionary<string, List<PlayMakerFSM>> groupsByFsmKey = ApplyPersistedEditsForScene(sceneName, components); _graphOverlay?.RefreshSnapshot(sceneName, components); _tabManager?.RebindAfterRefresh(groupsByFsmKey); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) PlayMakerFSM[] components = Object.FindObjectsByType<PlayMakerFSM>((FindObjectsInactive)1, (FindObjectsSortMode)0); Dictionary<string, List<PlayMakerFSM>> groupsByFsmKey = ApplyPersistedEditsForScene(((Scene)(ref scene)).name, components); FsmGraphOverlay? graphOverlay = _graphOverlay; if (graphOverlay != null) { Scene activeScene = SceneManager.GetActiveScene(); graphOverlay.RefreshSnapshot(((Scene)(ref activeScene)).name ?? string.Empty, components); } _tabManager?.RebindAfterRefresh(groupsByFsmKey); } private Dictionary<string, List<PlayMakerFSM>> ApplyPersistedEditsForScene(string sceneName, PlayMakerFSM[] components) { if (_editManager == null || _tabManager == null) { return new Dictionary<string, List<PlayMakerFSM>>(); } Dictionary<string, List<PlayMakerFSM>> dictionary = FsmIdentity.DiscoverFsmGroups(components); _editManager.ReplaceLiveInstances(dictionary.ToDictionary((KeyValuePair<string, List<PlayMakerFSM>> g) => g.Key, (KeyValuePair<string, List<PlayMakerFSM>> g) => g.Value.Select((PlayMakerFSM c) => c.Fsm).ToList())); ConfigEntry<bool> autoLoadConfig = _autoLoadConfig; if (autoLoadConfig == null || !autoLoadConfig.Value) { return dictionary; } IEnumerable<string> fsmKeysPresent = _tabManager.Tabs.Select((FsmTabState tab) => tab.FsmKey).Where(dictionary.ContainsKey); foreach (FsmEditSet item in FsmSaveDataStore.LoadLastChosenForScene(sceneName, fsmKeysPresent)) { _editManager.ApplyEditSet(item); } return dictionary; } public void ResetFsm(string sceneName, string fsmKey) { _editManager?.ResetFsm(fsmKey); FsmSaveDataStore.ClearAllSavesForFsm(sceneName, fsmKey); } } [HarmonyPatch(typeof(Fsm), "Preprocess", new Type[] { })] internal static class FsmActivatedPatch { [HarmonyPostfix] private static void Postfix(Fsm __instance) { FsmEditManager activeEditManagerForPatches = FsmMasterPlugin.ActiveEditManagerForPatches; if (activeEditManagerForPatches == null) { return; } PlayMakerFSM fsmComponent = __instance.FsmComponent; if (!((Object)(object)fsmComponent == (Object)null)) { string fsmKey = FsmIdentity.GetFsmKey(fsmComponent); activeEditManagerForPatches.ReconcileLiveInstance(fsmKey, __instance); FsmEditSet activeEditSet = activeEditManagerForPatches.GetActiveEditSet(fsmKey); if (activeEditSet != null) { activeEditManagerForPatches.ApplyEditSet(activeEditSet); } } } } [HarmonyPatch(typeof(InputHandler), "SetCursorVisible")] internal static class ForceCursorVisiblePatch { [HarmonyPrefix] private static void Prefix(ref bool value) { if (FsmMasterPlugin.ForceCursorVisible) { value = true; } } } internal sealed class ConfigurationManagerAttributes { public bool? Browsable; public bool? IsAdvanced; } internal sealed class DebugModCompat { private const string ActiveEditsCustomDataKey = "FsmMaster.ActiveEdits"; private readonly FsmEditManager _editManager; private readonly Action _rescanLiveFsms; private readonly ManualLogSource _logger; private DebugModCompat(FsmEditManager editManager, Action rescanLiveFsms, ManualLogSource logger) { _editManager = editManager; _rescanLiveFsms = rescanLiveFsms; _logger = logger; } public static DebugModCompat? TryCreate(FsmEditManager editManager, Action rescanLiveFsms, ManualLogSource logger) { if (!Chainloader.PluginInfos.ContainsKey("io.github.hk-speedrunning.debugmod")) { return null; } DebugModCompat debugModCompat = new DebugModCompat(editManager, rescanLiveFsms, logger); debugModCompat.Hook(); return debugModCompat; } private void Hook() { SaveState.OnSave += HandleSave; SaveState.AfterLoad += HandleAfterLoad; DebugMod.Log("FsmMaster detected DebugMod - hooking savestate save/load to persist active FSM edits."); } public void Unhook() { SaveState.OnSave -= HandleSave; SaveState.AfterLoad -= HandleAfterLoad; } private void HandleSave(SaveState state) { try { List<FsmEditSet> list = new List<FsmEditSet>(); foreach (string editedFsmKey in _editManager.GetEditedFsmKeys()) { FsmEditSet activeEditSet = _editManager.GetActiveEditSet(editedFsmKey); if (activeEditSet != null) { list.Add(activeEditSet); } } if (list.Count != 0) { state.data.customData["FsmMaster.ActiveEdits"] = FsmSaveDataStore.SerializeEditSets(list); DebugMod.Log($"FsmMaster saved {list.Count} active FSM edit set(s) into this savestate."); } } catch (Exception ex) { _logger.LogWarning((object)("[FsmMaster] Failed to save FSM edits into DebugMod savestate: " + ex.Message)); } } private void HandleAfterLoad(SaveState state) { try { _rescanLiveFsms(); if (!state.data.customData.TryGetValue("FsmMaster.ActiveEdits", out var value) || string.IsNullOrEmpty(value)) { return; } List<FsmEditSet> list = FsmSaveDataStore.DeserializeEditSets(value); foreach (FsmEditSet item in list) { _editManager.ApplyEditSet(item); } DebugMod.Log($"FsmMaster restored {list.Count} FSM edit set(s) from this savestate."); } catch (Exception ex) { _logger.LogWarning((object)("[FsmMaster] Failed to restore FSM edits from DebugMod savestate: " + ex.Message)); } } } internal sealed class FsmActiveStateTracker { private sealed class TrackedFsm { public Fsm Instance; public Action<FsmState> Handler; public readonly HashSet<string> EnteredSinceCommit = new HashSet<string>(); public readonly Dictionary<string, float> FadingStates = new Dictionary<string, float>(); } private const float FadeDurationSeconds = 1f; private readonly Dictionary<string, TrackedFsm> _tracked = new Dictionary<string, TrackedFsm>(); private readonly HashSet<string> _visibleThisFrame = new HashSet<string>(); public void EnsureTracked(string fsmKey, Fsm instance) { _visibleThisFrame.Add(fsmKey); if (_tracked.TryGetValue(fsmKey, out TrackedFsm value)) { if (value.Instance == instance) { return; } Fsm instance2 = value.Instance; instance2.StateChanged = (Action<FsmState>)Delegate.Remove(instance2.StateChanged, value.Handler); _tracked.Remove(fsmKey); } TrackedFsm entry = new TrackedFsm { Instance = instance }; entry.Handler = delegate(FsmState state) { entry.EnteredSinceCommit.Add(state.Name); }; instance.StateChanged = (Action<FsmState>)Delegate.Combine(instance.StateChanged, entry.Handler); _tracked[fsmKey] = entry; } public void CommitFrame() { List<string> list = null; foreach (KeyValuePair<string, TrackedFsm> item in _tracked) { string key = item.Key; TrackedFsm value = item.Value; if ((Object)(object)value.Instance.FsmComponent == (Object)null || !_visibleThisFrame.Contains(key)) { Fsm instance = value.Instance; instance.StateChanged = (Action<FsmState>)Delegate.Remove(instance.StateChanged, value.Handler); (list ?? (list = new List<string>())).Add(key); continue; } string activeStateName = value.Instance.ActiveStateName; foreach (string item2 in value.EnteredSinceCommit) { if (item2 == activeStateName) { value.FadingStates.Remove(item2); } else { value.FadingStates[item2] = Time.unscaledTime; } } value.EnteredSinceCommit.Clear(); if (value.FadingStates.Count <= 0) { continue; } List<string> list2 = null; foreach (KeyValuePair<string, float> fadingState in value.FadingStates) { if (Time.unscaledTime - fadingState.Value >= 1f) { (list2 ?? (list2 = new List<string>())).Add(fadingState.Key); } } if (list2 == null) { continue; } foreach (string item3 in list2) { value.FadingStates.Remove(item3); } } if (list != null) { foreach (string item4 in list) { _tracked.Remove(item4); } } _visibleThisFrame.Clear(); } public float? GetFadeProgress(string fsmKey, string stateName) { if (!_tracked.TryGetValue(fsmKey, out TrackedFsm value) || !value.FadingStates.TryGetValue(stateName, out var value2)) { return null; } return Mathf.Clamp01((Time.unscaledTime - value2) / 1f); } public bool HasAnyFading(string fsmKey) { if (_tracked.TryGetValue(fsmKey, out TrackedFsm value)) { return value.FadingStates.Count > 0; } return false; } public void UnsubscribeAll() { foreach (TrackedFsm value in _tracked.Values) { Fsm instance = value.Instance; instance.StateChanged = (Action<FsmState>)Delegate.Remove(instance.StateChanged, value.Handler); } _tracked.Clear(); _visibleThisFrame.Clear(); } } internal sealed class FsmConsoleLogger { private readonly ManualLogSource _logger; public FsmConsoleLogger(ManualLogSource logger) { _logger = logger; } public void LogSnapshot(FsmSnapshot snapshot) { _logger.LogInfo((object)$"[FsmMaster] Scene \"{snapshot.SceneName}\": {snapshot.Fsms.Count} live PlayMakerFSM instance(s)"); foreach (FsmIdentityInfo fsm in snapshot.Fsms) { if (!((Object)(object)fsm.Component == (Object)null)) { LogFsm(FsmDataCollector.CollectFsmInfo(fsm.Component)); } } } public void LogFsm(FsmInfo fsm) { _logger.LogInfo((object)("[FsmMaster] FSM \"" + fsm.FsmName + "\" on \"" + fsm.GameObjectName + "\" - state \"" + fsm.ActiveStateName + "\"")); LogFsmDetails(fsm); } private void LogFsmDetails(FsmInfo fsm) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) _logger.LogInfo((object)$"[FsmMaster] {fsm.States.Count} state(s)"); foreach (FsmStateInfo state in fsm.States) { _logger.LogInfo((object)("[FsmMaster] State \"" + state.Name + "\"")); Rect position = state.State.Position; _logger.LogInfo((object)FormattableString.Invariant($"[FsmMaster] Position=({((Rect)(ref position)).x:F1}, {((Rect)(ref position)).y:F1}, {((Rect)(ref position)).width:F1}, {((Rect)(ref position)).height:F1}) ColorIndex={state.State.ColorIndex}")); LogActions(state.Actions); foreach (FsmTransitionInfo transition in state.Transitions) { _logger.LogInfo((object)("[FsmMaster] \"" + transition.EventName + "\" -> \"" + transition.ToState + "\"")); } } if (fsm.GlobalTransitions.Count > 0) { _logger.LogInfo((object)$"[FsmMaster] {fsm.GlobalTransitions.Count} global transition(s)"); foreach (FsmTransitionInfo globalTransition in fsm.GlobalTransitions) { _logger.LogInfo((object)("[FsmMaster] \"" + globalTransition.EventName + "\" -> \"" + globalTransition.ToState + "\"")); } } LogFsmVariables(fsm.Fsm.Variables); } private void LogActions(IReadOnlyList<FsmActionInfo> actions) { _logger.LogInfo((object)$"[FsmMaster] {actions.Count} action(s)"); for (int i = 0; i < actions.Count; i++) { FsmActionInfo fsmActionInfo = actions[i]; _logger.LogInfo((object)$"[FsmMaster] [{i}] {fsmActionInfo.ActionType.Name}"); foreach (FsmActionFieldInfo field in fsmActionInfo.Fields) { LogActionField(fsmActionInfo.Action, field.FieldName, field.FieldValue); } } } private void LogActionField(FsmStateAction action, string fieldName, object? fieldValue) { FsmArray val = (FsmArray)((fieldValue is FsmArray) ? fieldValue : null); if (val == null) { Array array = fieldValue as Array; if (array != null) { LogActionFieldArray(action, fieldName, array.Length, (int i) => array.GetValue(i)); } else { _logger.LogInfo((object)("[FsmMaster] " + fieldName + ": " + FormatActionFieldValue(action, fieldValue))); } } else { LogActionFieldArray(action, WithVariableName(fieldName, ((NamedVariable)val).Name), val.Length, (int i) => val.Values[i]); } } private static string WithVariableName(string fieldName, string variableName) { if (string.IsNullOrEmpty(variableName)) { return fieldName; } return fieldName + " (\"" + variableName + "\")"; } private void LogActionFieldArray(FsmStateAction action, string fieldName, int length, Func<int, object?> getElement) { _logger.LogInfo((object)$"[FsmMaster] {fieldName}: {length} element(s)"); for (int i = 0; i < length; i++) { object fieldValue = getElement(i); _logger.LogInfo((object)$"[FsmMaster] [{i}]: {FormatActionFieldValue(action, fieldValue)}"); } } internal static string FormatActionFieldValue(FsmStateAction action, object? fieldValue) { if (fieldValue != null) { NamedVariable val = (NamedVariable)((fieldValue is NamedVariable) ? fieldValue : null); if (val == null) { FsmEvent val2 = (FsmEvent)((fieldValue is FsmEvent) ? fieldValue : null); if (val2 == null) { FsmOwnerDefault val3 = (FsmOwnerDefault)((fieldValue is FsmOwnerDefault) ? fieldValue : null); if (val3 == null) { FsmEventTarget val4 = (FsmEventTarget)((fieldValue is FsmEventTarget) ? fieldValue : null); if (val4 != null) { return FormatEventTarget(action.Fsm, val4); } return fieldValue.ToString(); } return FormatOwnerDefault(action.Fsm, val3); } return val2.Name; } string text = val.RawValue?.ToString() ?? "null"; if (string.IsNullOrEmpty(val.Name)) { return text; } return "\"" + val.Name + "\": " + text; } return "null"; } internal static string FormatOwnerDefault(Fsm? fsm, FsmOwnerDefault ownerDefault) { if (fsm == null) { return "[uninitialized]"; } GameObject ownerDefaultTarget = fsm.GetOwnerDefaultTarget(ownerDefault); if (!((Object)(object)ownerDefaultTarget != (Object)null)) { return "[none]"; } return "[" + ((Object)ownerDefaultTarget).name + "]"; } internal static string FormatEventTarget(Fsm? fsm, FsmEventTarget eventTarget) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) EventTarget target = eventTarget.target; switch ((int)target) { case 0: return "EventTarget(Self)"; case 1: return "EventTarget(GameObject): " + FormatOwnerDefault(fsm, eventTarget.gameObject); case 2: { string text2 = eventTarget.fsmName.Value ?? ""; return "EventTarget(GameObjectFSM): " + FormatOwnerDefault(fsm, eventTarget.gameObject) + "." + text2; } case 3: { PlayMakerFSM fsmComponent = eventTarget.fsmComponent; string text = (((Object)(object)fsmComponent != (Object)null) ? (((Object)((Component)fsmComponent).gameObject).name + "." + fsmComponent.FsmName) : "none"); return "EventTarget(FSMComponent): [" + text + "]"; } default: return $"EventTarget({eventTarget.target})"; } } private void LogFsmVariables(FsmVariables variables) { _logger.LogInfo((object)"[FsmMaster] Variables"); LogVariableArray<FsmFloat>("Float", variables.FloatVariables, (Func<FsmFloat, object>)((FsmFloat v) => v.Value)); LogVariableArray<FsmInt>("Int", variables.IntVariables, (Func<FsmInt, object>)((FsmInt v) => v.Value)); LogVariableArray<FsmBool>("Bool", variables.BoolVariables, (Func<FsmBool, object>)((FsmBool v) => v.Value)); LogVariableArray<FsmString>("String", variables.StringVariables, (Func<FsmString, object>)((FsmString v) => v.Value)); LogVariableArray<FsmVector2>("Vector2", variables.Vector2Variables, (Func<FsmVector2, object>)((FsmVector2 v) => v.Value)); LogVariableArray<FsmVector3>("Vector3", variables.Vector3Variables, (Func<FsmVector3, object>)((FsmVector3 v) => v.Value)); LogVariableArray<FsmRect>("Rect", variables.RectVariables, (Func<FsmRect, object>)((FsmRect v) => v.Value)); LogVariableArray<FsmQuaternion>("Quaternion", variables.QuaternionVariables, (Func<FsmQuaternion, object>)((FsmQuaternion v) => v.Value)); LogVariableArray<FsmColor>("Color", variables.ColorVariables, (Func<FsmColor, object>)((FsmColor v) => v.Value)); LogVariableArray<FsmGameObject>("GameObject", variables.GameObjectVariables, (Func<FsmGameObject, object>)((FsmGameObject v) => v.Value)); LogVariableArray<FsmObject>("Object", variables.ObjectVariables, (Func<FsmObject, object>)((FsmObject v) => v.Value)); LogVariableArray<FsmMaterial>("Material", variables.MaterialVariables, (Func<FsmMaterial, object>)((FsmMaterial v) => v.Value)); LogVariableArray<FsmTexture>("Texture", variables.TextureVariables, (Func<FsmTexture, object>)((FsmTexture v) => v.Value)); LogVariableArray<FsmEnum>("Enum", variables.EnumVariables, (Func<FsmEnum, object>)((FsmEnum v) => v.Value)); LogVariableArray<FsmArray>("Array", variables.ArrayVariables, (Func<FsmArray, object>)((FsmArray v) => string.Join(", ", v.Values))); } private void LogVariableArray<T>(string typeName, T[] items, Func<T, object> getValue) where T : NamedVariable { if (items.Length != 0) { foreach (T val in items) { _logger.LogInfo((object)$"[FsmMaster] {typeName} \"{((NamedVariable)val).Name}\": {getValue(val)}"); } } } } internal sealed class FsmSnapshot { public string SceneName { get; set; } = ""; public IReadOnlyList<FsmIdentityInfo> Fsms { get; set; } = Array.Empty<FsmIdentityInfo>(); } internal sealed class FsmIdentityInfo { public PlayMakerFSM Component { get; set; } public string FsmName { get; set; } = ""; public string GameObjectName { get; set; } = ""; } internal sealed class FsmInfo { public PlayMakerFSM Component { get; set; } public Fsm Fsm { get; set; } public string FsmName { get; set; } = ""; public string GameObjectName { get; set; } = ""; public string ActiveStateName { get; set; } = ""; public IReadOnlyList<FsmStateInfo> States { get; set; } = Array.Empty<FsmStateInfo>(); public IReadOnlyList<FsmTransitionInfo> GlobalTransitions { get; set; } = Array.Empty<FsmTransitionInfo>(); } internal sealed class FsmStateInfo { public FsmState State { get; set; } public string Name { get; set; } = ""; public IReadOnlyList<FsmActionInfo> Actions { get; set; } = Array.Empty<FsmActionInfo>(); public IReadOnlyList<FsmTransitionInfo> Transitions { get; set; } = Array.Empty<FsmTransitionInfo>(); } internal sealed class FsmActionInfo { public FsmStateAction Action { get; set; } public Type ActionType { get; set; } public IReadOnlyList<FsmActionFieldInfo> Fields { get; set; } = Array.Empty<FsmActionFieldInfo>(); } internal sealed class FsmActionFieldInfo { public string FieldName { get; set; } = ""; public object? FieldValue { get; set; } public FieldInfo Field { get; set; } public bool IsHidden { get; set; } } internal sealed class FsmTransitionInfo { public string EventName { get; set; } = ""; public string ToState { get; set; } = ""; } internal static class FsmDataCollector { private static readonly Dictionary<Type, FieldInfo[]> RelevantFieldsByActionType = new Dictionary<Type, FieldInfo[]>(); public static FsmSnapshot CollectSnapshot(string sceneName, PlayMakerFSM[] components) { List<FsmIdentityInfo> list = new List<FsmIdentityInfo>(components.Length); foreach (PlayMakerFSM val in components) { list.Add(new FsmIdentityInfo { Component = val, FsmName = val.FsmName, GameObjectName = ((Object)((Component)val).gameObject).name }); } return new FsmSnapshot { SceneName = sceneName, Fsms = list }; } public static FsmInfo CollectFsmInfo(PlayMakerFSM component) { Fsm fsm = component.Fsm; List<FsmStateInfo> list = new List<FsmStateInfo>(fsm.States.Length); FsmState[] states = fsm.States; foreach (FsmState state in states) { list.Add(CollectStateInfo(state)); } return new FsmInfo { Component = component, Fsm = fsm, FsmName = component.FsmName, GameObjectName = ((Object)((Component)component).gameObject).name, ActiveStateName = component.ActiveStateName, States = list, GlobalTransitions = CollectTransitions(fsm.GlobalTransitions) }; } private static FsmStateInfo CollectStateInfo(FsmState state) { return new FsmStateInfo { State = state, Name = state.Name, Actions = CollectActions(state.Actions), Transitions = CollectTransitions(state.Transitions) }; } private static FieldInfo[] GetRelevantFields(Type actionType) { if (RelevantFieldsByActionType.TryGetValue(actionType, out FieldInfo[] value)) { return value; } List<FieldInfo> list = new List<FieldInfo>(); FieldInfo[] fields = actionType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.DeclaringType == typeof(FsmStateAction)) && !fieldInfo.IsDefined(typeof(CompilerGeneratedAttribute), inherit: false)) { list.Add(fieldInfo); } } FieldInfo[] array = list.ToArray(); RelevantFieldsByActionType[actionType] = array; return array; } private static IReadOnlyList<FsmActionInfo> CollectActions(FsmStateAction[] actions) { List<FsmActionInfo> list = new List<FsmActionInfo>(actions.Length); foreach (FsmStateAction val in actions) { Type type = ((object)val).GetType(); FieldInfo[] relevantFields = GetRelevantFields(type); List<FsmActionFieldInfo> list2 = new List<FsmActionFieldInfo>(relevantFields.Length); FieldInfo[] array = relevantFields; foreach (FieldInfo fieldInfo in array) { list2.Add(new FsmActionFieldInfo { FieldName = fieldInfo.Name, FieldValue = fieldInfo.GetValue(val), Field = fieldInfo, IsHidden = !fieldInfo.IsPublic }); } list.Add(new FsmActionInfo { Action = val, ActionType = type, Fields = list2 }); } return list; } private static IReadOnlyList<FsmTransitionInfo> CollectTransitions(FsmTransition[] transitions) { List<FsmTransitionInfo> list = new List<FsmTransitionInfo>(transitions.Length); foreach (FsmTransition val in transitions) { list.Add(new FsmTransitionInfo { EventName = val.EventName, ToState = val.ToState }); } return list; } } internal static class FsmIdentity { private static readonly Regex DuplicateSuffixPattern = new Regex("^(?<base>.+) \\(\\d+\\)$", RegexOptions.Compiled); public static string GetObjectBaseName(string gameObjectName) { Match match = DuplicateSuffixPattern.Match(gameObjectName); if (!match.Success) { return gameObjectName; } return match.Groups["base"].Value; } public static string GetFsmKey(string baseObjectName, string fsmName) { return baseObjectName + "::" + fsmName; } public static string GetFsmKey(PlayMakerFSM component) { return GetFsmKey(GetObjectBaseName(((Object)((Component)component).gameObject).name), component.FsmName); } public static Dictionary<string, List<PlayMakerFSM>> DiscoverFsmGroups(IEnumerable<PlayMakerFSM> components) { Dictionary<string, List<PlayMakerFSM>> dictionary = new Dictionary<string, List<PlayMakerFSM>>(); foreach (PlayMakerFSM component in components) { string fsmKey = GetFsmKey(component); if (!dictionary.TryGetValue(fsmKey, out var value)) { value = (dictionary[fsmKey] = new List<PlayMakerFSM>()); } value.Add(component); } return dictionary; } } internal sealed class FsmPristineSnapshot { public FsmEditSet OriginalValues { get; } = new FsmEditSet(); public Dictionary<string, List<int>> NeuteredActionIndices { get; } = new Dictionary<string, List<int>>(); public List<FsmStateAction> InjectedExitActions { get; } = new List<FsmStateAction>(); public List<(FsmStateAction Original, FsmStateAction Sequencer)> InstalledSequencers { get; } = new List<(FsmStateAction, FsmStateAction)>(); } internal static class FsmSaveDataStore { [Serializable] private sealed class FsmEditSetListWire { public List<string> EditSets = new List<string>(); } [Serializable] private sealed class FsmEditSetWire { public string FsmKey = ""; public List<string> VariableOverrides = new List<string>(); public List<string> ActionFieldOverrides = new List<string>(); public List<string> DisabledStates = new List<string>(); public List<string> TransitionRetargets = new List<string>(); public List<string> SequencerOverrides = new List<string>(); } internal static readonly string DataDirectory = Path.Combine(Application.persistentDataPath, "FsmMasterData"); private static readonly Dictionary<string, Dictionary<string, string>> LastChosenByScene = new Dictionary<string, Dictionary<string, string>>(); private const string PairSeparator = "; "; private const string KeyValueSeparator = "="; private const string PatternSeparator = ", "; private static string SanitizeForFileName(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { value = value.Replace(oldChar, '_'); } return value; } private static string GetSceneDirectory(string sceneName) { return Path.Combine(DataDirectory, SanitizeForFileName(sceneName)); } private static string GetFsmDirectory(string sceneName, string fsmKey) { return Path.Combine(GetSceneDirectory(sceneName), SanitizeForFileName(fsmKey)); } public static string GetFilePath(string sceneName, string fsmKey, string saveName) { return Path.Combine(GetFsmDirectory(sceneName, fsmKey), SanitizeForFileName(saveName) + ".json"); } public static FsmEditSet? Load(string sceneName, string fsmKey, string saveName) { string filePath = GetFilePath(sceneName, fsmKey, saveName); if (!File.Exists(filePath)) { return null; } return FromWire(JsonUtility.FromJson<FsmEditSetWire>(File.ReadAllText(filePath))); } public static List<string> ListSaveNames(string sceneName, string fsmKey) { List<string> list = new List<string>(); string fsmDirectory = GetFsmDirectory(sceneName, fsmKey); if (!Directory.Exists(fsmDirectory)) { return list; } foreach (string item in Directory.EnumerateFiles(fsmDirectory, "*.json")) { list.Add(Path.GetFileNameWithoutExtension(item)); } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } public static string Save(string sceneName, string saveName, FsmEditSet edits) { string fsmDirectory = GetFsmDirectory(sceneName, edits.FsmKey); if (!Directory.Exists(fsmDirectory)) { Directory.CreateDirectory(fsmDirectory); } string text = JsonUtility.ToJson((object)ToWire(edits), true); File.WriteAllText(GetFilePath(sceneName, edits.FsmKey, saveName), text); return text; } public static void ClearAllSavesForFsm(string sceneName, string fsmKey) { string fsmDirectory = GetFsmDirectory(sceneName, fsmKey); if (Directory.Exists(fsmDirectory)) { Directory.Delete(fsmDirectory, recursive: true); } if (LastChosenByScene.TryGetValue(sceneName, out Dictionary<string, string> value)) { value.Remove(fsmKey); } } public static List<FsmEditSet> LoadLastChosenForScene(string sceneName, IEnumerable<string> fsmKeysPresent) { List<FsmEditSet> list = new List<FsmEditSet>(); List<string> list2 = ((fsmKeysPresent is List<string> list3) ? list3 : fsmKeysPresent.ToList()); if (list2.Count == 0 || !LastChosenByScene.TryGetValue(sceneName, out Dictionary<string, string> value)) { return list; } foreach (string item in list2) { if (value.TryGetValue(item, out var value2)) { FsmEditSet fsmEditSet = Load(sceneName, item, value2); if (fsmEditSet != null) { list.Add(fsmEditSet); } } } return list; } public static string? GetLastChosenSaveName(string sceneName, string fsmKey) { if (!LastChosenByScene.TryGetValue(sceneName, out Dictionary<string, string> value) || !value.TryGetValue(fsmKey, out var value2)) { return null; } return value2; } public static void SetLastChosenSaveName(string sceneName, string fsmKey, string saveName) { if (!LastChosenByScene.TryGetValue(sceneName, out Dictionary<string, string> value)) { value = new Dictionary<string, string>(); LastChosenByScene[sceneName] = value; } value[fsmKey] = saveName; } public static string SerializeEditSets(IEnumerable<FsmEditSet> editSets) { FsmEditSetListWire fsmEditSetListWire = new FsmEditSetListWire(); foreach (FsmEditSet editSet in editSets) { fsmEditSetListWire.EditSets.Add(JsonUtility.ToJson((object)ToWire(editSet))); } return JsonUtility.ToJson((object)fsmEditSetListWire); } public static List<FsmEditSet> DeserializeEditSets(string json) { List<FsmEditSet> list = new List<FsmEditSet>(); FsmEditSetListWire fsmEditSetListWire = JsonUtility.FromJson<FsmEditSetListWire>(json); if (fsmEditSetListWire == null) { return list; } foreach (string editSet in fsmEditSetListWire.EditSets) { list.Add(FromWire(JsonUtility.FromJson<FsmEditSetWire>(editSet))); } return list; } private static string JoinPairs(params string[] keysAndValues) { List<string> list = new List<string>(keysAndValues.Length / 2); for (int i = 0; i + 1 < keysAndValues.Length; i += 2) { list.Add(keysAndValues[i] + "=" + keysAndValues[i + 1]); } return string.Join("; ", list); } private static Dictionary<string, string> SplitPairs(string joined) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string[] array = joined.Split("; "); foreach (string text in array) { int num = text.IndexOf("=", StringComparison.Ordinal); if (num >= 0) { dictionary[text.Substring(0, num)] = text.Substring(num + 1); } } return dictionary; } private static FsmEditSetWire ToWire(FsmEditSet edits) { FsmEditSetWire fsmEditSetWire = new FsmEditSetWire { FsmKey = edits.FsmKey }; foreach (VariableOverride variableOverride in edits.VariableOverrides) { fsmEditSetWire.VariableOverrides.Add(JoinPairs("type", variableOverride.VariableType, "name", variableOverride.Name, "array", variableOverride.ArrayIndex.ToString(CultureInfo.InvariantCulture), "value", variableOverride.StringValue)); } foreach (ActionFieldOverride actionFieldOverride in edits.ActionFieldOverrides) { fsmEditSetWire.ActionFieldOverrides.Add(JoinPairs("state", actionFieldOverride.StateName, "action", actionFieldOverride.ActionIndex.ToString(CultureInfo.InvariantCulture), "type", actionFieldOverride.ExpectedActionTypeName, "field", actionFieldOverride.FieldName, "array", actionFieldOverride.ArrayIndex.ToString(CultureInfo.InvariantCulture), "value", actionFieldOverride.StringValue)); } fsmEditSetWire.DisabledStates.AddRange(edits.DisabledStates); foreach (TransitionRetarget transitionRetarget in edits.TransitionRetargets) { fsmEditSetWire.TransitionRetargets.Add(JoinPairs("state", transitionRetarget.StateName, "event", transitionRetarget.EventName, "newState", transitionRetarget.NewStateName, "newTo", transitionRetarget.NewToState, "newEvent", transitionRetarget.NewEventName)); } foreach (SequencerOverride sequencerOverride in edits.SequencerOverrides) { fsmEditSetWire.SequencerOverrides.Add(JoinPairs("state", sequencerOverride.StateName, "action", sequencerOverride.ActionIndex.ToString(CultureInfo.InvariantCulture), "repeat", sequencerOverride.RepeatCount.ToString(CultureInfo.InvariantCulture), "pattern", string.Join(", ", sequencerOverride.Pattern))); } return fsmEditSetWire; } private static FsmEditSet FromWire(FsmEditSetWire? wire) { FsmEditSet fsmEditSet = new FsmEditSet(); if (wire == null) { return fsmEditSet; } fsmEditSet.FsmKey = wire.FsmKey; foreach (string variableOverride in wire.VariableOverrides) { Dictionary<string, string> dictionary = SplitPairs(variableOverride); fsmEditSet.VariableOverrides.Add(new VariableOverride { VariableType = dictionary["type"], Name = dictionary["name"], ArrayIndex = (dictionary.TryGetValue("array", out var value) ? int.Parse(value, CultureInfo.InvariantCulture) : (-1)), StringValue = dictionary["value"] }); } foreach (string actionFieldOverride in wire.ActionFieldOverrides) { Dictionary<string, string> dictionary2 = SplitPairs(actionFieldOverride); fsmEditSet.ActionFieldOverrides.Add(new ActionFieldOverride { StateName = dictionary2["state"], ActionIndex = int.Parse(dictionary2["action"], CultureInfo.InvariantCulture), ExpectedActionTypeName = dictionary2["type"], FieldName = dictionary2["field"], ArrayIndex = (dictionary2.TryGetValue("array", out var value2) ? int.Parse(value2, CultureInfo.InvariantCulture) : (-1)), StringValue = dictionary2["value"] }); } fsmEditSet.DisabledStates.AddRange(wire.DisabledStates); foreach (string transitionRetarget in wire.TransitionRetargets) { Dictionary<string, string> dictionary3 = SplitPairs(transitionRetarget); fsmEditSet.TransitionRetargets.Add(new TransitionRetarget { StateName = dictionary3["state"], EventName = dictionary3["event"], NewStateName = dictionary3["newState"], NewToState = dictionary3["newTo"], NewEventName = (dictionary3.TryGetValue("newEvent", out var value3) ? value3 : "") }); } foreach (string sequencerOverride2 in wire.SequencerOverrides) { Dictionary<string, string> dictionary4 = SplitPairs(sequencerOverride2); SequencerOverride sequencerOverride = new SequencerOverride { StateName = dictionary4["state"], ActionIndex = int.Parse(dictionary4["action"], CultureInfo.InvariantCulture), RepeatCount = int.Parse(dictionary4["repeat"], CultureInfo.InvariantCulture) }; if (dictionary4.TryGetValue("pattern", out var value4) && value4.Length > 0) { sequencerOverride.Pattern.AddRange(value4.Split(", ")); } fsmEditSet.SequencerOverrides.Add(sequencerOverride); } return fsmEditSet; } } internal sealed class FsmVariableTracker { private readonly Func<string, IReadOnlyList<Fsm>> _getLiveInstances; private readonly List<TrackedVariablePath> _tracked = new List<TrackedVariablePath>(); private readonly List<TrackedVariableValue> _resultBuffer = new List<TrackedVariableValue>(); public int Version { get; private set; } public FsmVariableTracker(Func<string, IReadOnlyList<Fsm>> getLiveInstances) { _getLiveInstances = getLiveInstances; } public void TrackVariable(string fsmKey, string variableName) { AddIfAbsent(new TrackedVariablePath(fsmKey, variableName, null, -1, null)); } public void TrackActionField(string fsmKey, string stateName, int actionIndex, string fieldName) { AddIfAbsent(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName)); } public void TrackState(string fsmKey, string stateName) { AddIfAbsent(new TrackedVariablePath(fsmKey, null, stateName, -1, null)); } public void TrackVariableArrayElement(string fsmKey, string variableName, int arrayIndex) { AddIfAbsent(new TrackedVariablePath(fsmKey, variableName, null, -1, null, arrayIndex)); } public void TrackActionFieldArrayElement(string fsmKey, string stateName, int actionIndex, string fieldName, int arrayIndex) { AddIfAbsent(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName, arrayIndex)); } private void AddIfAbsent(TrackedVariablePath path) { if (!_tracked.Contains(path)) { _tracked.Add(path); Version++; } } public void UntrackVariable(string fsmKey, string variableName) { if (_tracked.Remove(new TrackedVariablePath(fsmKey, variableName, null, -1, null))) { Version++; } } public void UntrackActionField(string fsmKey, string stateName, int actionIndex, string fieldName) { if (_tracked.Remove(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName))) { Version++; } } public void UntrackState(string fsmKey, string stateName) { if (_tracked.Remove(new TrackedVariablePath(fsmKey, null, stateName, -1, null))) { Version++; } } public void UntrackVariableArrayElement(string fsmKey, string variableName, int arrayIndex) { if (_tracked.Remove(new TrackedVariablePath(fsmKey, variableName, null, -1, null, arrayIndex))) { Version++; } } public void UntrackActionFieldArrayElement(string fsmKey, string stateName, int actionIndex, string fieldName, int arrayIndex) { if (_tracked.Remove(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName, arrayIndex))) { Version++; } } public bool IsVariableTracked(string fsmKey, string variableName) { return _tracked.Contains(new TrackedVariablePath(fsmKey, variableName, null, -1, null)); } public bool IsActionFieldTracked(string fsmKey, string stateName, int actionIndex, string fieldName) { return _tracked.Contains(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName)); } public bool IsStateTracked(string fsmKey, string stateName) { return _tracked.Contains(new TrackedVariablePath(fsmKey, null, stateName, -1, null)); } public bool IsVariableArrayElementTracked(string fsmKey, string variableName, int arrayIndex) { return _tracked.Contains(new TrackedVariablePath(fsmKey, variableName, null, -1, null, arrayIndex)); } public bool IsActionFieldArrayElementTracked(string fsmKey, string stateName, int actionIndex, string fieldName, int arrayIndex) { return _tracked.Contains(new TrackedVariablePath(fsmKey, null, stateName, actionIndex, fieldName, arrayIndex)); } public IReadOnlyList<TrackedVariableValue> GetTracked() { while (_resultBuffer.Count < _tracked.Count) { _resultBuffer.Add(new TrackedVariableValue()); } if (_resultBuffer.Count > _tracked.Count) { _resultBuffer.RemoveRange(_tracked.Count, _resultBuffer.Count - _tracked.Count); } for (int i = 0; i < _tracked.Count; i++) { TrackedVariablePath trackedVariablePath = _tracked[i]; IReadOnlyList<Fsm> readOnlyList = _getLiveInstances(trackedVariablePath.FsmKey); Fsm val = ((readOnlyList.Count > 0) ? readOnlyList[0] : null); TrackedVariableValue trackedVariableValue = _resultBuffer[i]; trackedVariableValue.FsmKey = trackedVariablePath.FsmKey; trackedVariableValue.DisplayLabel = trackedVariablePath.DisplayLabel; trackedVariableValue.CurrentValue = ((val == null) ? "<no live instance>" : ResolveCurrentValue(val, trackedVariablePath)); } return _resultBuffer; } private static string ResolveCurrentValue(Fsm fsm, TrackedVariablePath path) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) int? arrayIndex; if (path.VariableName != null) { NamedVariable val = fsm.Variables.FindVariable(path.VariableName); if (val == null) { return "<not found>"; } arrayIndex = path.ArrayIndex; if (arrayIndex.HasValue) { int valueOrDefault = arrayIndex.GetValueOrDefault(); FsmArray val2 = (FsmArray)(object)((val is FsmArray) ? val : null); if (val2 == null || valueOrDefault >= val2.Length) { return "<not found>"; } return FsmEditManager.FormatArrayElement(val2.ElementType, val2.Get(valueOrDefault)); } return FormatValue(val.RawValue); } if (path.ActionIndex < 0 && path.FieldName == null) { if (fsm.GetState(path.StateName) != null) { if (!(fsm.ActiveStateName == path.StateName)) { return "Inactive"; } return "Active"; } return "<not found>"; } FsmState state = fsm.GetState(path.StateName); if (state == null || path.ActionIndex < 0 || path.ActionIndex >= state.Actions.Length) { return "<not found>"; } FsmStateAction val3 = state.Actions[path.ActionIndex]; FieldInfo field = ((object)val3).GetType().GetField(path.FieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return "<not found>"; } object value = field.GetValue(val3); arrayIndex = path.ArrayIndex; if (arrayIndex.HasValue) { int valueOrDefault2 = arrayIndex.GetValueOrDefault(); if (!(value is Array array) || valueOrDefault2 >= array.Length) { return "<not found>"; } object value2 = array.GetValue(valueOrDefault2); NamedVariable val4 = (NamedVariable)((value2 is NamedVariable) ? value2 : null); return FormatValue((val4 != null) ? val4.RawValue : value2); } NamedVariable val5 = (NamedVariable)((value is NamedVariable) ? value : null); return FormatValue((val5 != null) ? val5.RawValue : value); } private static string FormatValue(object? value) { return value?.ToString() ?? "null"; } } internal sealed class TrackedVariablePath : IEquatable<TrackedVariablePath> { public string FsmKey { get; } public string? VariableName { get; } public string? StateName { get; } public int ActionIndex { get; } public string? FieldName { get; } public int? ArrayIndex { get; } public string DisplayLabel { get; } public TrackedVariablePath(string fsmKey, string? variableName, string? stateName, int actionIndex, string? fieldName, int? arrayIndex = null) { FsmKey = fsmKey; VariableName = variableName; StateName = stateName; ActionIndex = actionIndex; FieldName = fieldName; ArrayIndex = arrayIndex; string text; if (VariableName == null) { if (FieldName == null) { text = fsmKey + " / " + stateName + " (state)"; } else if (arrayIndex.HasValue) { int valueOrDefault = arrayIndex.GetValueOrDefault(); text = $"{fsmKey} / {stateName}[{actionIndex}].{fieldName}[{valueOrDefault}]"; } else { text = $"{fsmKey} / {stateName}[{actionIndex}].{fieldName}"; } } else if (arrayIndex.HasValue) { int valueOrDefault2 = arrayIndex.GetValueOrDefault(); text = $"{fsmKey} / {variableName}[{valueOrDefault2}]"; } else { text = fsmKey + " / " + variableName; } DisplayLabel = text; } public bool Equals(TrackedVariablePath? other) { if (other != null && FsmKey == other.FsmKey && VariableName == other.VariableName && StateName == other.StateName && ActionIndex == other.ActionIndex && FieldName == other.FieldName) { return ArrayIndex == other.ArrayIndex; } return false; } public override bool Equals(object? obj) { return Equals(obj as TrackedVariablePath); } public override int GetHashCode() { return HashCode.Combine(FsmKey, VariableName, StateName, ActionIndex, FieldName, ArrayIndex); } } internal sealed class TrackedVariableValue { public string FsmKey = ""; public string DisplayLabel = ""; public string CurrentValue = ""; } internal sealed class SequenceSendEventAction : FsmStateAction { private readonly FsmEvent[] _sequence; private readonly int _repeatCount; private readonly FsmStateAction _originalAction; private readonly FsmState _state; private int _index; private int _completedCycles; public SequenceSendEventAction(FsmEvent[] sequence, int repeatCount, FsmStateAction originalAction, FsmState state) { if (sequence.Length == 0) { throw new ArgumentException("Sequence must contain at least one event.", "sequence"); } _sequence = sequence; _repeatCount = repeatCount; _originalAction = originalAction; _state = state; } public override void OnEnter() { if (_repeatCount > 0 && _completedCycles >= _repeatCount) { RestoreOriginalAction(); _originalAction.OnEnter(); return; } ((FsmStateAction)this).Fsm.Event(_sequence[_index]); _index++; if (_index >= _sequence.Length) { _index = 0; _completedCycles++; } ((FsmStateAction)this).Finish(); } private void RestoreOriginalAction() { _originalAction.Enabled = true; int num = Array.IndexOf(_state.Actions, (FsmStateAction)(object)this); if (num >= 0) { FsmUtil.RemoveAction(_state, num); } } } internal static class FsmActionSequencer { public static int IndexRandomEventAction(FsmState state, int rank) { int num = 0; for (int i = 0; i < state.Actions.Length; i++) { if (((object)state.Actions[i]).GetType().Name.Contains("Random")) { if (num == rank) { return i; } num++; } } return -1; } public static FsmEvent[] ExtractEventCandidates(FsmStateAction sourceAction, FsmState state) { FieldInfo fieldInfo = ((object)sourceAction).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((FieldInfo f) => f.FieldType == typeof(FsmEvent[])); if (fieldInfo != null && fieldInfo.GetValue(sourceAction) is FsmEvent[] result) { return result; } return state.Transitions.Select((FsmTransition t) => t.FsmEvent).ToArray(); } public static FsmEvent[] ExpandPattern(FsmEvent[] events, int[] repeatCounts) { List<FsmEvent> list = new List<FsmEvent>(); for (int i = 0; i < repeatCounts.Length; i++) { for (int j = 0; j < repeatCounts[i]; j++) { list.Add(events[i]); } } return list.ToArray(); } } internal sealed class FsmEditManager { private sealed class SendExitEventAction : FsmStateAction { private readonly FsmEvent _exitEvent; public SendExitEventAction(FsmEvent exitEvent) { _exitEvent = exitEvent; } public override void OnEnter() { ((FsmStateAction)this).Fsm.Event(_exitEvent); ((FsmStateAction)this).Finish(); } } private static readonly string[] ExitEventPriority = new string[3] { "CANCEL", "FINISHED", "NEXT" }; private static readonly HashSet<VariableType> SupportedVariableTypes = new HashSet<VariableType> { (VariableType)0, (VariableType)1, (VariableType)2, (VariableType)4, (VariableType)5, (VariableType)6, (VariableType)8, (VariableType)11, (VariableType)7, (VariableType)14 }; private static readonly HashSet<VariableType> SupportedArrayElementTypes = new HashSet<VariableType> { (VariableType)0, (VariableType)1, (VariableType)2, (VariableType)4 }; private readonly ManualLogSource _logger; private readonly Dictionary<string, List<Fsm>> _liveInstances = new Dictionary<string, List<Fsm>>(); private readonly Dictionary<string, FsmPristineSnapshot> _pristine = new Dictionary<string, FsmPristineSnapshot>(); private readonly Dictionary<string, FsmEditSet> _activeEdits = new Dictionary<string, FsmEditSet>(); private readonly Dictionary<string, Stack<Action>> _undoStacks = new Dictionary<string, Stack<Action>>(); private bool _isUndoing; private readonly HashSet<string> _pendingActivationFsmKeys = new HashSet<string>(); public int EditGeneration { get; private set; } private void BumpEditGeneration() { EditGeneration++; } public FsmEditManager(ManualLogSource logger) { _logger = logger; } public void ReplaceLiveInstances(IReadOnlyDictionary<string, List<Fsm>> instancesByKey) { _liveInstances.Clear(); foreach (KeyValuePair<string, List<Fsm>> item in instancesByKey) { _liveInstances[item.Key] = item.Value; } PruneStaleSnapshotEntries(); } private void PruneStaleSnapshotEntries() { foreach (KeyValuePair<string, FsmPristineSnapshot> item in _pristine) { HashSet<Fsm> alive = new HashSet<Fsm>(GetLiveInstances(item.Key)); item.Value.InjectedExitActions.RemoveAll((FsmStateAction action) => !alive.Contains(action.State.Fsm)); item.Value.InstalledSequencers.RemoveAll(((FsmStateAction Original, FsmStateAction Sequencer) pair) => !alive.Contains(pair.Sequencer.State.Fsm)); } } public IReadOnlyList<Fsm> GetLiveInstances(string fsmKey) { if (!_liveInstances.TryGetValue(fsmKey, out List<Fsm> value)) { return Array.Empty<Fsm>(); } return value; } public void ReconcileLiveInstance(string fsmKey, Fsm fsm) { if (!_liveInstances.TryGetValue(fsmKey, out List<Fsm> value)) { value = new List<Fsm>(); _liveInstances[fsmKey] = value; } value.RemoveAll((Fsm existing) => existing != fsm && (Object)(object)existing.FsmComponent == (Object)(object)fsm.FsmComponent); if (!value.Contains(fsm)) { value.Add(fsm); } } public void PollPendingActivations() { if (_pendingActivationFsmKeys.Count == 0) { return; } string[] array = _pendingActivationFsmKeys.ToArray(); foreach (string text in array) { _pendingActivationFsmKeys.Remove(text); FsmEditSet activeEditSet = GetActiveEditSet(text); if (activeEditSet == null) { continue; } Fsm[] array2 = GetLiveInstances(text).ToArray(); for (int j = 0; j < array2.Length; j++) { PlayMakerFSM fsmComponent = array2[j].FsmComponent; if (fsmComponent != null) { Fsm fsm = fsmComponent.Fsm; if (fsm != null) { ReconcileLiveInstance(text, fsm); } } } ApplyEditSet(activeEditSet); } } public IReadOnlyCollection<string> GetEditedFsmKeys() { return _activeEdits.Keys; } public FsmEditSet? GetActiveEditSet(string fsmKey) { if (!_activeEdits.TryGetValue(fsmKey, out FsmEditSet value)) { return null; } return value; } public void ApplyEditSet(FsmEditSet editSet) { if (!_liveInstances.TryGetValue(editSet.FsmKey, out List<Fsm> value) || value.Count == 0) { _logger.LogWarning((object)("[FsmMaster] No live instances found for fsm key '" + editSet.FsmKey + "'; skipping edit set.")); return; } VariableOverride[] array = editSet.VariableOverrides.ToArray(); ActionFieldOverride[] array2 = editSet.ActionFieldOverrides.ToArray(); string[] array3 = editSet.DisabledStates.ToArray(); TransitionRetarget[] array4 = editSet.TransitionRetargets.ToArray(); SequencerOverride[] array5 = editSet.SequencerOverrides.ToArray(); foreach (Fsm item in value) { VariableOverride[] array6 = array; foreach (VariableOverride ov in array6) { ApplyVariableOverride(editSet.FsmKey, item, ov); } ActionFieldOverride[] array7 = array2; foreach (ActionFieldOverride ov2 in array7) { ApplyActionFieldOverride(editSet.FsmKey, item, ov2); } string[] array8 = array3; foreach (string stateName in array8) { DisableState(editSet.FsmKey, item, stateName); } TransitionRetarget[] array9 = array4; foreach (TransitionRetarget retarget in array9) { ApplyTransitionRetarget(editSet.FsmKey, item, retarget); } SequencerOverride[] array10 = array5; foreach (SequencerOverride seq in array10) { InstallSequencer(editSet.FsmKey, item, seq); } } } public void ResetFsm(string fsmKey) { if (_pristine.TryGetValue(fsmKey, out FsmPristineSnapshot value)) { _liveInstances.TryGetValue(fsmKey, out List<Fsm> value2); RestoreSnapshot(value, value2 ?? new List<Fsm>()); _pristine.Remove(fsmKey); _activeEdits.Remove(fsmKey); _undoStacks.Remove(fsmKey); BumpEditGeneration(); } } public void RevertAllForUnload() { foreach (KeyValuePair<string, FsmPristineSnapshot> item in _pristine) { _liveInstances.TryGetValue(item.Key, out List<Fsm> value); RestoreSnapshot(item.Value, value ?? new List<Fsm>()); } _pristine.Clear(); _liveInstances.Clear(); _activeEdits.Clear(); _undoStacks.Clear(); } public bool HasUndo(string fsmKey) { if (_undoStacks.TryGetValue(fsmKey, out Stack<Action> value)) { return value.Count > 0; } return false; } public void Undo(string fsmKey) { if (!_undoStacks.TryGetValue(fsmKey, out Stack<Action> value) || value.Count == 0) { return; } Action action = value.Pop(); _isUndoing = true; try { action(); } finally { _isUndoing = false; } } private void PushUndo(string fsmKey, Action undo) { if (!_isUndoing) { if (!_undoStacks.TryGetValue(fsmKey, out Stack<Action> value)) { value = new Stack<Action>(); _undoStacks[fsmKey] = value; } value.Push(undo); } } public void SetVariable(string fsmKey, string variableName, string variableType, string stringValue) { string previousValue = GetCurrentVariableValue(fsmKey, variableName); VariableOverride ov = new VariableOverride { VariableType = variableType, Name = variableName, StringValue = stringValue }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyVariableOverride(fsmKey, liveInstance, ov); } if (previousValue != null) { PushUndo(fsmKey, delegate { SetVariable(fsmKey, variableName, variableType, previousValue); }); } } public void SetActionField(string fsmKey, string stateName, int actionIndex, string expectedActionTypeName, string fieldName, string stringValue) { string previousValue = GetCurrentActionFieldValue(fsmKey, stateName, actionIndex, expectedActionTypeName, fieldName); ActionFieldOverride ov = new ActionFieldOverride { StateName = stateName, ActionIndex = actionIndex, ExpectedActionTypeName = expectedActionTypeName, FieldName = fieldName, StringValue = stringValue }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyActionFieldOverride(fsmKey, liveInstance, ov); } if (previousValue != null) { PushUndo(fsmKey, delegate { SetActionField(fsmKey, stateName, actionIndex, expectedActionTypeName, fieldName, previousValue); }); } } public void SetVariableArrayElement(string fsmKey, string variableName, int arrayIndex, string elementStringValue) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) string previousValue = GetCurrentVariableArrayElementValue(fsmKey, variableName, arrayIndex); VariableOverride ov = new VariableOverride { VariableType = ((object)(VariableType)13/*cast due to .constrained prefix*/).ToString(), Name = variableName, ArrayIndex = arrayIndex, StringValue = elementStringValue }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyVariableOverride(fsmKey, liveInstance, ov); } if (previousValue != null) { PushUndo(fsmKey, delegate { SetVariableArrayElement(fsmKey, variableName, arrayIndex, previousValue); }); } } public void SetActionFieldArrayElement(string fsmKey, string stateName, int actionIndex, string expectedActionTypeName, string fieldName, int arrayIndex, string elementStringValue) { string previousValue = GetCurrentActionFieldArrayElementValue(fsmKey, stateName, actionIndex, expectedActionTypeName, fieldName, arrayIndex); ActionFieldOverride ov = new ActionFieldOverride { StateName = stateName, ActionIndex = actionIndex, ExpectedActionTypeName = expectedActionTypeName, FieldName = fieldName, ArrayIndex = arrayIndex, StringValue = elementStringValue }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyActionFieldOverride(fsmKey, liveInstance, ov); } if (previousValue != null) { PushUndo(fsmKey, delegate { SetActionFieldArrayElement(fsmKey, stateName, actionIndex, expectedActionTypeName, fieldName, arrayIndex, previousValue); }); } } private string? GetCurrentVariableValue(string fsmKey, string variableName) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { NamedVariable val = liveInstance.Variables.FindVariable(variableName); if (val != null && SupportedVariableTypes.Contains(val.VariableType)) { return FormatNamedVariable(val); } } return null; } private string? GetCurrentVariableArrayElementValue(string fsmKey, string variableName, int arrayIndex) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { NamedVariable obj = liveInstance.Variables.FindVariable(variableName); FsmArray val = (FsmArray)(object)((obj is FsmArray) ? obj : null); if (val != null && arrayIndex < val.Length) { return FormatArrayElement(val.ElementType, val.Get(arrayIndex)); } } return null; } private string? GetCurrentActionFieldValue(string fsmKey, string stateName, int actionIndex, string expectedActionTypeName, string fieldName) { foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { if (TryFindActionField(liveInstance, stateName, actionIndex, expectedActionTypeName, fieldName, out FsmStateAction action, out FieldInfo field) && TryFormatValue(field.GetValue(action), out string formatted)) { return formatted; } } return null; } private string? GetCurrentActionFieldArrayElementValue(string fsmKey, string stateName, int actionIndex, string expectedActionTypeName, string fieldName, int arrayIndex) { foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { if (TryFindActionField(liveInstance, stateName, actionIndex, expectedActionTypeName, fieldName, out FsmStateAction action, out FieldInfo field) && field.GetValue(action) is Array array && arrayIndex < array.Length && TryFormatValue(array.GetValue(arrayIndex), out string formatted)) { return formatted; } } return null; } private static bool TryFindActionField(Fsm fsm, string stateName, int actionIndex, string expectedActionTypeName, string fieldName, [NotNullWhen(true)] out FsmStateAction? action, [NotNullWhen(true)] out FieldInfo? field) { action = null; field = null; FsmState state = fsm.GetState(stateName); if (state == null || actionIndex < 0 || actionIndex >= state.Actions.Length) { return false; } FsmStateAction val = state.Actions[actionIndex]; if (((object)val).GetType().Name != expectedActionTypeName) { return false; } FieldInfo field2 = ((object)val).GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 == null) { return false; } action = val; field = field2; return true; } public void ApplyVariableOverride(string fsmKey, Fsm fsm, VariableOverride ov) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) NamedVariable val = fsm.Variables.FindVariable(ov.Name); if (val == null) { _logger.LogWarning((object)("[FsmMaster] Variable '" + ov.Name + "' not found on fsm '" + fsm.Name + "'; skipping.")); return; } if (ov.ArrayIndex >= 0) { ApplyVariableArrayElementOverride(fsmKey, fsm, val, ov); return; } if (!SupportedVariableTypes.Contains(val.VariableType)) { _logger.LogWarning((object)$"[FsmMaster] Variable '{ov.Name}' on fsm '{fsm.Name}' has unsupported type '{val.VariableType}' (object/array-reference variables are out of scope for this pass); skipping."); return; } if (((object)val.VariableType/*cast due to .constrained prefix*/).ToString() != ov.VariableType) { _logger.LogWarning((object)$"[FsmMaster] Variable '{ov.Name}' on fsm '{fsm.Name}' is now type '{val.VariableType}', expected '{ov.VariableType}'; skipping."); return; } FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.OriginalValues.VariableOverrides.Exists((VariableOverride v) => v.Name == ov.Name && v.ArrayIndex == -1)) { orCreateSnapshot.OriginalValues.VariableOverrides.Add(new VariableOverride { VariableType = ((object)val.VariableType/*cast due to .constrained prefix*/).ToString(), Name = ov.Name, StringValue = FormatNamedVariable(val) }); } AssignNamedVariable(val, ov.StringValue); FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.VariableOverrides.RemoveAll((VariableOverride v) => v.Name == ov.Name && v.ArrayIndex == -1); orCreateActiveEditSet.VariableOverrides.Add(ov); BumpEditGeneration(); } private void ApplyVariableArrayElementOverride(string fsmKey, Fsm fsm, NamedVariable variable, VariableOverride ov) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) FsmArray val = (FsmArray)(object)((variable is FsmArray) ? variable : null); if (val == null) { _logger.LogWarning((object)("[FsmMaster] Variable '" + ov.Name + "' on fsm '" + fsm.Name + "' is not an array; skipping element edit.")); return; } if (!SupportedArrayElementTypes.Contains(val.ElementType)) { _logger.LogWarning((object)$"[FsmMaster] Variable '{ov.Name}' on fsm '{fsm.Name}' has unsupported array element type '{val.ElementType}'; skipping."); return; } if (ov.ArrayIndex >= val.Length) { _logger.LogWarning((object)$"[FsmMaster] Variable '{ov.Name}' on fsm '{fsm.Name}' array index {ov.ArrayIndex} is out of range (length {val.Length}); skipping."); return; } FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.OriginalValues.VariableOverrides.Exists((VariableOverride v) => v.Name == ov.Name && v.ArrayIndex == ov.ArrayIndex)) { orCreateSnapshot.OriginalValues.VariableOverrides.Add(new VariableOverride { VariableType = ov.VariableType, Name = ov.Name, ArrayIndex = ov.ArrayIndex, StringValue = FormatArrayElement(val.ElementType, val.Get(ov.ArrayIndex)) }); } AssignArrayElement(val, ov.ArrayIndex, ov.StringValue); FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.VariableOverrides.RemoveAll((VariableOverride v) => v.Name == ov.Name && v.ArrayIndex == ov.ArrayIndex); orCreateActiveEditSet.VariableOverrides.Add(ov); BumpEditGeneration(); } private static void AssignArrayElement(FsmArray array, int index, string stringValue) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) array.Set(index, ParseArrayElement(array.ElementType, stringValue)); array.SaveChanges(); } internal static bool IsSupportedArrayElementType(VariableType elementType) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return SupportedArrayElementTypes.Contains(elementType); } internal static string FormatArrayElement(VariableType elementType, object? rawValue) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) return (int)elementType switch { 0 => Convert.ToSingle(rawValue, CultureInfo.InvariantCulture).ToString("R", CultureInfo.InvariantCulture), 1 => Convert.ToInt32(rawValue, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture), 2 => Convert.ToBoolean(rawValue).ToString(CultureInfo.InvariantCulture), 4 => (rawValue as string) ?? "", _ => throw new NotSupportedException($"Array element type '{elementType}' is not supported for editing."), }; } private static object ParseArrayElement(VariableType elementType, string stringValue) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) return (int)elementType switch { 0 => float.Parse(stringValue, CultureInfo.InvariantCulture), 1 => int.Parse(stringValue, CultureInfo.InvariantCulture), 2 => bool.Parse(stringValue), 4 => stringValue, _ => throw new NotSupportedException($"Array element type '{elementType}' is not supported for editing."), }; } public void ApplyActionFieldOverride(string fsmKey, Fsm fsm, ActionFieldOverride ov) { FsmState state = fsm.GetState(ov.StateName); if (state == null || ov.ActionIndex < 0 || ov.ActionIndex >= state.Actions.Length) { _logger.LogWarning((object)$"[FsmMaster] State '{ov.StateName}' action index {ov.ActionIndex} not found on fsm '{fsm.Name}'; skipping."); return; } FsmStateAction val = state.Actions[ov.ActionIndex]; if (((object)val).GetType().Name != ov.ExpectedActionTypeName) { _logger.LogWarning((object)$"[FsmMaster] Action at '{ov.StateName}'[{ov.ActionIndex}] on fsm '{fsm.Name}' is '{((object)val).GetType().Name}', expected '{ov.ExpectedActionTypeName}'; skipping."); return; } FieldInfo field = ((object)val).GetType().GetField(ov.FieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { _logger.LogWarning((object)("[FsmMaster] Field '" + ov.FieldName + "' not found on action '" + ov.ExpectedActionTypeName + "'; skipping.")); return; } object value = field.GetValue(val); if (ov.ArrayIndex >= 0) { ApplyActionFieldArrayElementOverride(fsmKey, ov, value); return; } if (!TryFormatValue(value, out string formatted)) { _logger.LogWarning((object)("[FsmMaster] Field '" + ov.FieldName + "' on '" + ov.ExpectedActionTypeName + "' has unsupported type '" + (value?.GetType().Name ?? "null") + "'; skipping.")); return; } FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.OriginalValues.ActionFieldOverrides.Exists((ActionFieldOverride f) => f.StateName == ov.StateName && f.ActionIndex == ov.ActionIndex && f.FieldName == ov.FieldName && f.ArrayIndex == -1)) { orCreateSnapshot.OriginalValues.ActionFieldOverrides.Add(new ActionFieldOverride { StateName = ov.StateName, ActionIndex = ov.ActionIndex, ExpectedActionTypeName = ov.ExpectedActionTypeName, FieldName = ov.FieldName, StringValue = formatted }); } TryAssignFieldValue(val, field, value, ov.StringValue); FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.ActionFieldOverrides.RemoveAll((ActionFieldOverride f) => f.StateName == ov.StateName && f.ActionIndex == ov.ActionIndex && f.FieldName == ov.FieldName && f.ArrayIndex == -1); orCreateActiveEditSet.ActionFieldOverrides.Add(ov); BumpEditGeneration(); } private void ApplyActionFieldArrayElementOverride(string fsmKey, ActionFieldOverride ov, object? fieldValue) { //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown if (!(fieldValue is Array array) || ov.ArrayIndex >= array.Length) { _logger.LogWarning((object)$"[FsmMaster] Field '{ov.FieldName}' on '{ov.ExpectedActionTypeName}' has no array element at index {ov.ArrayIndex}; skipping."); return; } object value = array.GetValue(ov.ArrayIndex); if (!TryFormatValue(value, out string formatted)) { _logger.LogWarning((object)string.Format("[FsmMaster] Field '{0}[{1}]' on '{2}' has unsupported type '{3}'; skipping.", ov.FieldName, ov.ArrayIndex, ov.ExpectedActionTypeName, value?.GetType().Name ?? "null")); return; } FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.OriginalValues.ActionFieldOverrides.Exists((ActionFieldOverride f) => f.StateName == ov.StateName && f.ActionIndex == ov.ActionIndex && f.FieldName == ov.FieldName && f.ArrayIndex == ov.ArrayIndex)) { orCreateSnapshot.OriginalValues.ActionFieldOverrides.Add(new ActionFieldOverride { StateName = ov.StateName, ActionIndex = ov.ActionIndex, ExpectedActionTypeName = ov.ExpectedActionTypeName, FieldName = ov.FieldName, ArrayIndex = ov.ArrayIndex, StringValue = formatted }); } AssignNamedVariable((NamedVariable)value, ov.StringValue); FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.ActionFieldOverrides.RemoveAll((ActionFieldOverride f) => f.StateName == ov.StateName && f.ActionIndex == ov.ActionIndex && f.FieldName == ov.FieldName && f.ArrayIndex == ov.ArrayIndex); orCreateActiveEditSet.ActionFieldOverrides.Add(ov); BumpEditGeneration(); } private static void RestoreActionField(Fsm fsm, ActionFieldOverride ov) { FsmState state = fsm.GetState(ov.StateName); if (state == null || ov.ActionIndex < 0 || ov.ActionIndex >= state.Actions.Length) { return; } FsmStateAction val = state.Actions[ov.ActionIndex]; FieldInfo field = ((object)val).GetType().GetField(ov.FieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return; } object value = field.GetValue(val); if (ov.ArrayIndex >= 0) { if (value is Array array && ov.ArrayIndex < array.Length) { object? value2 = array.GetValue(ov.ArrayIndex); NamedVariable val2 = (NamedVariable)((value2 is NamedVariable) ? value2 : null); if (val2 != null) { AssignNamedVariable(val2, ov.StringValue); } } } else { TryAssignFieldValue(val, field, value, ov.StringValue); } } public void DisableState(string fsmKey, string stateName) { FsmPristineSnapshot value; bool flag = _pristine.TryGetValue(fsmKey, out value) && value.NeuteredActionIndices.ContainsKey(stateName); foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { DisableState(fsmKey, liveInstance, stateName); } if (!flag) { PushUndo(fsmKey, delegate { EnableState(fsmKey, stateName); }); } } public void EnableState(string fsmKey, string stateName) { if (!_pristine.TryGetValue(fsmKey, out FsmPristineSnapshot value) || !value.NeuteredActionIndices.TryGetValue(stateName, out List<int> value2)) { return; } foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { FsmState state = liveInstance.GetState(stateName); if (state == null) { continue; } foreach (int item in value2) { if (item >= 0 && item < state.Actions.Length) { state.Actions[item].Enabled = true; } } FsmStateAction val = ((IEnumerable<FsmStateAction>)state.Actions).FirstOrDefault((Func<FsmStateAction, bool>)((FsmStateAction a) => a is SendExitEventAction)); if (val != null) { int num = Array.IndexOf(state.Actions, val); if (num >= 0) { FsmUtil.RemoveAction(state, num); } value.InjectedExitActions.Remove(val); } } value.NeuteredActionIndices.Remove(stateName); if (_activeEdits.TryGetValue(fsmKey, out FsmEditSet value3)) { value3.DisabledStates.Remove(stateName); } PushUndo(fsmKey, delegate { DisableState(fsmKey, stateName); }); BumpEditGeneration(); } public void DisableState(string fsmKey, Fsm fsm, string stateName) { FsmState state = fsm.GetState(stateName); if (state == null) { _logger.LogWarning((object)("[FsmMaster] State '" + stateName + "' not found on fsm '" + fsm.Name + "'; skipping disable.")); } else { if (state.Actions.Any((FsmStateAction a) => a is SendExitEventAction)) { return; } FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.NeuteredActionIndices.ContainsKey(stateName)) { List<int> list = new List<int>(); for (int num = 0; num < state.Actions.Length; num++) { if (state.Actions[num].Enabled) { state.Actions[num].Enabled = false; list.Add(num); } } orCreateSnapshot.NeuteredActionIndices[stateName] = list; } FsmEvent val = FindExitEvent(state); if (val != null) { SendExitEventAction sendExitEventAction = new SendExitEventAction(val); FsmUtil.AddAction(state, (FsmStateAction)(object)sendExitEventAction); orCreateSnapshot.InjectedExitActions.Add((FsmStateAction)(object)sendExitEventAction); } else if (!state.IsInitialized) { _logger.LogWarning((object)("[FsmMaster] Fsm '" + fsm.Name + "' hasn't activated yet (owning object inactive); state '" + stateName + "' has its actions disabled but its exit event can't be resolved until this instance activates.")); _pendingActivationFsmKeys.Add(fsmKey); } else { _logger.LogWarning((object)("[FsmMaster] State '" + stateName + "' on fsm '" + fsm.Name + "' has no CANCEL/FINISHED/NEXT transition and no FsmEvent-valued action field to fall back on; leaving it inert with no exit.")); } FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); if (!orCreateActiveEditSet.DisabledStates.Contains(stateName)) { orCreateActiveEditSet.DisabledStates.Add(stateName); } BumpEditGeneration(); } } internal static FsmEvent? FindExitEvent(FsmState state) { string[] exitEventPriority = ExitEventPriority; foreach (string text in exitEventPriority) { FsmTransition val = FsmUtil.GetTransition(state, text) ?? (state.IsInitialized ? FsmUtil.GetGlobalTransition(state.Fsm, text) : null); if (val != null) { return val.FsmEvent; } } FsmEvent result = null; FsmStateAction[] actions = state.Actions; foreach (FsmStateAction val2 in actions) { FieldInfo[] fields = ((object)val2).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); for (int j = 0; j < fields.Length; j++) { object value = fields[j].GetValue(val2); FsmEvent val3 = (FsmEvent)((value is FsmEvent) ? value : null); if (val3 == null) { if (value is FsmEvent[] array && array.Length > 0) { result = array[^1]; } } else { result = val3; } } } return result; } public void ApplyTransitionRetarget(string fsmKey, Fsm fsm, TransitionRetarget retarget) { bool flag = string.IsNullOrEmpty(retarget.StateName); FsmTransition val = (flag ? FsmUtil.GetGlobalTransition(fsm, retarget.EventName) : FsmUtil.GetTransition(fsm, retarget.StateName, retarget.EventName)); if (val == null) { string text = (flag ? "global transitions" : ("state '" + retarget.StateName + "'")); _logger.LogWarning((object)("[FsmMaster] Transition for event '" + retarget.EventName + "' not found on " + text + " on fsm '" + fsm.Name + "'; skipping.")); return; } string text2 = EffectiveNewEventName(retarget); FsmPristineSnapshot orCreateSnapshot = GetOrCreateSnapshot(fsmKey); if (!orCreateSnapshot.OriginalValues.TransitionRetargets.Exists((TransitionRetarget t) => t.StateName == retarget.StateName && t.EventName == retarget.EventName)) { bool flag2 = retarget.NewToState == "\0DISABLED"; orCreateSnapshot.OriginalValues.TransitionRetargets.Add(new TransitionRetarget { StateName = (flag2 ? retarget.StateName : retarget.NewStateName), EventName = (flag2 ? retarget.EventName : text2), NewStateName = retarget.StateName, NewEventName = retarget.EventName, NewToState = val.ToState }); } FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.TransitionRetargets.RemoveAll((TransitionRetarget t) => t.StateName == retarget.StateName && t.EventName == retarget.EventName); orCreateActiveEditSet.TransitionRetargets.Add(retarget); BumpEditGeneration(); if (retarget.NewToState == "\0DISABLED") { RemoveTransitionAt(fsm, retarget.StateName, retarget.EventName); } else { RelocateTransition(fsm, retarget.StateName, retarget.NewStateName, retarget.EventName, text2, retarget.NewToState); } } private static void RestoreTransition(Fsm fsm, TransitionRetarget original) { RelocateTransition(fsm, original.StateName, original.NewStateName, original.EventName, EffectiveNewEventName(original), original.NewToState); } private static void RelocateTransition(Fsm fsm, string fromStateName, string toStateName, string fromEventName, string toEventName, string newToState) { if (fromStateName != toStateName || fromEventName != toEventName) { RemoveTransitionAt(fsm, fromStateName, fromEventName); } AddOrChangeTransitionAt(fsm, toStateName, toEventName, newToState); } internal static string EffectiveNewEventName(TransitionRetarget retarget) { if (!string.IsNullOrEmpty(retarget.NewEventName)) { return retarget.NewEventName; } return retarget.EventName; } public void RetargetTransitionToState(string fsmKey, string stateName, string eventName, string newToState) { string previousToState = GetCurrentTransitionToState(fsmKey, stateName, eventName); TransitionRetarget retarget = new TransitionRetarget { StateName = stateName, EventName = eventName, NewStateName = stateName, NewToState = newToState }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyTransitionRetarget(fsmKey, liveInstance, retarget); } if (previousToState != null) { PushUndo(fsmKey, delegate { RetargetTransitionToState(fsmKey, stateName, eventName, previousToState); }); } } private string? GetCurrentTransitionToState(string fsmKey, string stateName, string eventName) { foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { FsmTransition val = (string.IsNullOrEmpty(stateName) ? FsmUtil.GetGlobalTransition(liveInstance, eventName) : FsmUtil.GetTransition(liveInstance, stateName, eventName)); if (val != null) { return val.ToState; } } return null; } public void DisableTransition(string fsmKey, string stateName, string eventName) { FsmPristineSnapshot value; bool flag = _pristine.TryGetValue(fsmKey, out value) && value.OriginalValues.TransitionRetargets.Exists((TransitionRetarget t) => t.NewStateName == stateName && EffectiveNewEventName(t) == eventName); TransitionRetarget retarget = new TransitionRetarget { StateName = stateName, EventName = eventName, NewStateName = stateName, NewToState = "\0DISABLED" }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { ApplyTransitionRetarget(fsmKey, liveInstance, retarget); } if (!flag) { PushUndo(fsmKey, delegate { EnableTransition(fsmKey, stateName, eventName); }); } } public void EnableTransition(string fsmKey, string stateName, string eventName) { if (!_pristine.TryGetValue(fsmKey, out FsmPristineSnapshot value)) { return; } TransitionRetarget transitionRetarget = value.OriginalValues.TransitionRetargets.Find((TransitionRetarget t) => t.NewStateName == stateName && EffectiveNewEventName(t) == eventName); if (transitionRetarget == null) { return; } foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { RestoreTransition(liveInstance, transitionRetarget); } value.OriginalValues.TransitionRetargets.Remove(transitionRetarget); if (_activeEdits.TryGetValue(fsmKey, out FsmEditSet value2)) { value2.TransitionRetargets.RemoveAll((TransitionRetarget t) => t.StateName == stateName && t.EventName == eventName); } PushUndo(fsmKey, delegate { DisableTransition(fsmKey, stateName, eventName); }); BumpEditGeneration(); } public void RetargetTransitionEvent(string fsmKey, string stateName, string eventName, string newOwnerStateName, string newEventName, string toState) { bool flag = newOwnerStateName == stateName && newEventName == eventName; TransitionRetarget retarget = new TransitionRetarget { StateName = stateName, EventName = eventName, NewStateName = newOwnerStateName, NewEventName = newEventName, NewToState = toState }; foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { if (!flag && (string.IsNullOrEmpty(newOwnerStateName) ? FsmUtil.GetGlobalTransition(liveInstance, newEventName) : FsmUtil.GetTransition(liveInstance, newOwnerStateName, newEventName)) != null) { RemoveTransitionAt(liveInstance, newOwnerStateName, newEventName); } ApplyTransitionRetarget(fsmKey, liveInstance, retarget); } if (!flag) { PushUndo(fsmKey, delegate { RetargetTransitionEvent(fsmKey, newOwnerStateName, newEventName, stateName, eventName, toState); }); } } private static void RemoveTransitionAt(Fsm fsm, string stateName, string eventName) { if (string.IsNullOrEmpty(stateName)) { FsmUtil.RemoveGlobalTransition(fsm, eventName); } else { FsmUtil.RemoveTransition(fsm, stateName, eventName); } } private static void AddOrChangeTransitionAt(Fsm fsm, string stateName, string eventName, string toState) { bool flag = string.IsNullOrEmpty(stateName); if (!(flag ? FsmUtil.ChangeGlobalTransition(fsm, eventName, toState) : FsmUtil.ChangeTransition(fsm, stateName, eventName, toState))) { if (flag) { FsmUtil.AddGlobalTransition(fsm, eventName, toState); } else { FsmUtil.AddTransition(fsm, stateName, eventName, toState); } } } public void InstallSequencer(string fsmKey, SequencerOverride seq) { foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { InstallSequencer(fsmKey, liveInstance, seq); } } public void InstallSequencer(string fsmKey, Fsm fsm, SequencerOverride seq) { FsmState state = fsm.GetState(seq.StateName); if (state == null) { _logger.LogWarning((object)("[FsmMaster] State '" + seq.StateName + "' not found on fsm '" + fsm.Name + "'; skipping sequencer install.")); return; } if (seq.Pattern.Count == 0) { _logger.LogWarning((object)("[FsmMaster] Sequencer pattern for state '" + seq.StateName + "' on fsm '" + fsm.Name + "' is empty; skipping.")); return; } int num = FsmActionSequencer.IndexRandomEventAction(state, seq.ActionIndex); if (num < 0) { _logger.LogWarning((object)$"[FsmMaster] No random-event action at rank {seq.ActionIndex} on state '{seq.StateName}' on fsm '{fsm.Name}'; skipping sequencer install."); return; } FsmEditSet orCreateActiveEditSet = GetOrCreateActiveEditSet(fsmKey); orCreateActiveEditSet.SequencerOverrides.RemoveAll((SequencerOverride s) => s.StateName == seq.StateName && s.ActionIndex == seq.ActionIndex); orCreateActiveEditSet.SequencerOverrides.Add(seq); FsmStateAction val = state.Actions[num]; if (val.State == null) { _logger.LogWarning((object)("[FsmMaster] Fsm '" + fsm.Name + "' hasn't activated yet (owning object inactive); sequencer override for state '" + seq.StateName + "' recorded but not installed on this instance.")); _pendingActivationFsmKeys.Add(fsmKey); BumpEditGeneration(); } else { RemoveInstalledSequencerFor(fsmKey, val, restoreOriginalEnabled: false); val.Enabled = false; SequenceSendEventAction sequenceSendEventAction = new SequenceSendEventAction(((IEnumerable<string>)seq.Pattern).Select((Func<string, FsmEvent>)FsmEvent.GetFsmEvent).ToArray(), seq.RepeatCount, val, state); FsmUtil.InsertActionAfter(val, (FsmStateAction)(object)sequenceSendEventAction); GetOrCreateSnapshot(fsmKey).InstalledSequencers.Add((val, (FsmStateAction)(object)sequenceSendEventAction)); BumpEditGeneration(); } } public void RemoveSequencer(string fsmKey, string stateName, int actionRank) { foreach (Fsm liveInstance in GetLiveInstances(fsmKey)) { FsmState state = liveInstance.GetState(stateName); if (state != null) { int num = FsmActionSequencer.IndexRandomEventAction(state, actionRank); if (num >= 0) { RemoveInstalledSequencerFor(fsmKey, state.Actions[num], restoreOriginalEnabled: true); } } } if (_activeEdits.TryGetValue(fsmKey, out FsmEditSet value)) { value.SequencerOverrides.RemoveAll((SequencerOverride s) => s.StateName == stateName && s.ActionIndex == actionRank); } BumpEditGeneration(); } private void RemoveInstalledSequencerFor(string fsmKey, FsmStateAction original, bool restoreOriginalEnabled) { if (!_pristine.TryGetValue(fsmKey, out FsmPristineSnapshot value)) { return; } int num = value.InstalledSequencers.FindIndex(((FsmStateAction Original, FsmStateAction Sequencer) p) => p.Original == original); if (num >= 0) { var (val, val2) = value.InstalledSequencers[num]; value.InstalledSequencers.RemoveAt(num); if (restoreOriginalEnabled) { val.Enable