Decompiled source of FsmMaster v0.2.7

plugins/FsmMaster.dll

Decompiled 3 hours ago
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