Decompiled source of DebugMod v1.10.0
DebugModPlus.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; 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; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Com.LuisPedroFonseca.ProCamera2D; using Cysharp.Threading.Tasks; using DebugModPlus.Interop; using DebugModPlus.Modules; using DebugModPlus.Modules.Hitbox; using DebugModPlus.Savestates; using DebugModPlus.Utils; using Febucci.UI.Core; using HarmonyLib; using I2.Loc; using InputExtension; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using MonsterLove.StateMachine; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using NineSolsAPI; using NineSolsAPI.Utils; using PrimeTween; using QFSW.QC; using RCGFSM.Animation; using RCGFSM.GameObjects; using RCGFSM.StateEvents; using RCGFSM.Transition; using RCGFSM.Variable; using RCGMaker.Core; using TAS; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Bindings; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.Tilemaps; using UnityEngine.UI; using mixpanel; [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("DebugModPlus")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Advanced Debug Mod for Nine Sols")] [assembly: AssemblyFileVersion("1.10.0.0")] [assembly: AssemblyInformationalVersion("1.10.0+b1a7da59347acfda3a492b8d141c71a974dcefad")] [assembly: AssemblyProduct("DebugModPlus")] [assembly: AssemblyTitle("DebugModPlus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.10.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 TAS { public static class DebugInfo { [Flags] public enum DebugFilter { Base = 0, RapidlyChanging = 1, Tweens = 2 } private const bool ShowClipInfo = true; private static readonly Regex ReNumPrefix = new Regex("\\d+_"); private static readonly Regex ReCjk = new Regex("_?\\p{IsCJKUnifiedIdeographs}+|^\\d+_"); public static string GetInfoText(DebugFilter filter = DebugFilter.Base) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Invalid comparison between Unknown and I4 //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_0587: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_05a9: Unknown result type (might be due to invalid IL or missing references) //IL_05ae: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0499: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) string text = ""; if (filter.HasFlag(DebugFilter.Tweens)) { Type type = typeof(Tween).Assembly.GetType("PrimeTween.PrimeTweenManager"); if ((object)type != null) { text += "Tweens:\n"; foreach (object item in ReflectionExtension.GetFieldValue<IList>(type.GetField("Instance", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null), "tweens")) { text += $"- {item}\n"; } text += "\n"; } } if (!SingletonBehaviour<ApplicationCore>.IsAvailable()) { return "Loading"; } if (!SingletonBehaviour<GameCore>.IsAvailable()) { text += "MainMenu\n"; return text + ((object)(PlayerInputStateType)(ref SingletonBehaviour<PlayerInputBinder>.Instance.currentStateType)).ToString(); } GameCore instance = SingletonBehaviour<GameCore>.Instance; if ((int)instance.currentCoreState != 1) { string enumName = typeof(GameCoreState).GetEnumName(instance.currentCoreState); text = text + enumName + "\n"; } Player player = instance.player; if (Object.op_Implicit((Object)(object)player)) { text += $"Pos: {Vector2.op_Implicit(((Component)player).transform.position)}\n"; text += $"Speed: {((Actor)player).FinalVelocity}\n"; text += $"HP: {player.health.CurrentHealthValue:0.00} (+{player.health.CurrentInternalInjury:0.00})\n"; string enumName2 = typeof(PlayerStateType).GetEnumName(player.fsm.State); PlayerInputStateType state = player.playerInput.fsm.State; text = text + "State: " + enumName2 + " " + (((int)state == 0) ? "" : ((object)(PlayerInputStateType)(ref state)).ToString()) + "\n"; MappingState val = player.fsm.FindMappingState(player.fsm.State); List<(bool, string)> flags = new List<(bool, string)>(9) { (player.isOnWall, "Wall"), (player.isOnLedge, "Ledge"), (player.isOnRope, "Rope"), (player.kicked, "Kicked"), (((Actor)player).onGround, "OnGround"), (player.lockMoving, "Locked"), (Object.op_Implicit((Object)(object)player.interactableFinder.CurrentInteractableArea), "CanInteract"), (player.rollCooldownTimer <= 0f, "CanDash"), (player.airJumpCount > 0, "AirJumping") }; (float, string)[] timers = new(float, string)[8] { (player.rollCooldownTimer, "RollCD"), (player.dashCooldownTimer, "DashCD"), (player.meleeAttackCooldownTimer, "AttackCD"), (player.parryCoolDownTimer, "ParryCD"), (player.gadgetCooldownTimer, "GadgetCD"), (player.grabHookCooldownTimer, "GrabHookCD"), (player.spinMoveCooldownTimer, "SpinMoveCD"), (player.jumpGraceTimer, "Coyote") }; text += Flags(flags, timers); PlayerAttackState val2 = (PlayerAttackState)(object)((val is PlayerAttackState) ? val : null); if (val2 != null) { string arg = (ReflectionExtension.GetFieldValue<bool>((object)val2, "CanDoMove") ? "" : "!"); string arg2 = (ReflectionExtension.GetFieldValue<bool>((object)val2, "isAir") ? "" : "!"); text += string.Format("Attack: {0}CanDoMove {1}IsAir {2}\n", arg, arg2, ReflectionExtension.GetFieldValue<int>((object)val2, "count")); } else { text += "\n"; } if ((int)player.jumpState != 0) { float currentVarJumpTimer = player.currentVarJumpTimer; float fieldValue = ReflectionExtension.GetFieldValue<float>((object)player, "GroundJumpRefrenceY"); float num = ((Component)player).transform.position.y - fieldValue; text += string.Format("JumpState {0} {1}h={2:0.00}\n", player.jumpState, (currentVarJumpTimer > 0f) ? (currentVarJumpTimer.ToString("0.00") + " ") : "", num); } else { text += "\n"; } text += AnimationText(((Actor)player).animator, filter.HasFlag(DebugFilter.RapidlyChanging)); } HackDrone hackDrone = ((PlayerHackDroneControlState)player.fsm.FindMappingState((PlayerStateType)61)).hackDrone; if (hackDrone.fsm != null && (int)hackDrone.fsm.State != 0) { text += $"\nNymph {hackDrone.fsm.State}\n"; text += $" Position: {Vector2.op_Implicit(((Component)hackDrone).transform.position)}\n"; text += $" Speed: {Vector2.op_Implicit(hackDrone.droneVel)}\n"; text = text + " " + Flags(new <>z__ReadOnlyArray<(bool, string)>(new(bool, string)[2] { (ReflectionExtension.GetFieldValue<bool>((object)hackDrone, "isDashCD"), "DashCD"), (ReflectionExtension.GetFieldValue<bool>((object)hackDrone, "isOutOfRange"), "OutOfRange") }), new <>z__ReadOnlySingleElementList<(float, string)>((ReflectionExtension.GetFieldValue<float>((object)hackDrone, "OutOfRangeTimer"), "OutOfRange")), " "); text = text + AnimationText(((Actor)hackDrone).animator, filter.HasFlag(DebugFilter.RapidlyChanging)) + "\n"; } GameLevel gameLevel = instance.gameLevel; if (Object.op_Implicit((Object)(object)gameLevel)) { text += $"[{gameLevel.SceneName}] ({gameLevel.BlockCountX}x{gameLevel.BlockCountY})"; if (filter.HasFlag(DebugFilter.RapidlyChanging)) { text += $" dt={Time.deltaTime:0.00000000}\n"; } text += "\n"; } if (Object.op_Implicit((Object)(object)instance.currentCutScene)) { text += $"{instance.currentCutScene}"; } return text; } private static string Flags(IEnumerable<(bool, string)> flags, IEnumerable<(float, string)> timers, string sep = "\n") { string text = GeneralExtensions.Join<(bool, string)>(flags.Where<(bool, string)>(((bool, string) x) => x.Item1), (Func<(bool, string), string>)(((bool, string) x) => x.Item2), " "); string text2 = GeneralExtensions.Join<(float, string)>(timers.Where<(float, string)>(((float, string) x) => x.Item1 > 0f), (Func<(float, string), string>)(((float, string) x) => $"{x.Item2}({x.Item1:0.000})"), " "); return text + sep + text2 + "\n"; } private static string AnimationText(Animator animator, bool includeRapidlyChanging) { //IL_0002: 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_0009: Unknown result type (might be due to invalid IL or missing references) AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0); string text = animator.ResolveHash(currentAnimatorStateInfo.m_Name); string text2 = "Animation " + text; if (includeRapidlyChanging) { text2 += $" {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime % 1f * 100f:00.0}%"; } return text2 + "\n"; } public static string GetMonsterInfotext() { string text = ""; foreach (MonsterBase value in SingletonBehaviour<MonsterManager>.Instance.monsterDict.Values) { if (((Behaviour)value).isActiveAndEnabled) { text = text + GetMonsterInfotext(value) + "\n"; } } return text; } public static string GetMonsterInfotext(MonsterBase monster) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) string text = ""; text = text + MonsterName(monster) + "\n"; text += $"Pos: {Vector2.op_Implicit(((Component)monster).transform.position)}\n"; text += $"Speed: {((PhysicsMover)monster).Velocity} + {Vector2.op_Implicit(((Actor)monster).AnimationVelocity)}\n"; text += $"HP: {monster.health.currentValue:0.00}\n"; if (monster.monsterCore.attackSequenceMoodule.getCurrentSequence() != null) { text += "TODO: attack sequence\n"; } if (monster.fsm == null) { return text + "FSM is null?\n"; } MappingState val = monster.fsm.FindMappingState(monster.fsm.State); AnimatorStateInfo currentAnimatorStateInfo = ((Actor)monster).animator.GetCurrentAnimatorStateInfo(0); text = text + "State: " + FsmStateName(val); text += $" {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime % 1f * 100f:00}%"; text += "\n"; BossGeneralState val2 = (BossGeneralState)(object)((val is BossGeneralState) ? val : null); if (val2 != null) { if (Object.op_Implicit((Object)(object)val2.attackQueue)) { text += "AttackQueue:\n"; foreach (States queuedAttack in val2.attackQueue.QueuedAttacks) { text = text + "- " + FsmStateName(monster.fsm, queuedAttack) + "\n"; } } text += "Queue:\n"; foreach (States queuedAttack2 in val2.QueuedAttacks) { text = text + "- " + FsmStateName(monster.fsm, queuedAttack2) + "\n"; } if ((Object)(object)((MonsterState)val2).clip != (Object)null) { text += "Clip:\n"; text += $"- {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime:0.00}\n"; AnimationEvent[] events = ((MonsterState)val2).clip.events; foreach (AnimationEvent val3 in events) { AnimationEvent val4 = (AnimationEvent)val3.intParameter; text += $"- {val3.time:0.00}: {val4}\n"; } } } MonsterHurtInterrupt hurtInterrupt = monster.HurtInterrupt; if (((Behaviour)hurtInterrupt).isActiveAndEnabled) { float fieldValue = ReflectionExtension.GetFieldValue<float>((object)hurtInterrupt, "AccumulateDamageTh"); if (fieldValue > 0f) { text += $"Hurt Interrupt: {hurtInterrupt.currentAccumulateDamage / (float)monster.postureSystem.FullPostureValue:0.00} > {fieldValue}\n"; } } _ = (bool)typeof(MonsterBase).GetMethod("MonsterStatCanCriticalHit", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(monster, Array.Empty<object>()); text += "Attack sensors:\n"; foreach (AttackSensor item in VersionCompatExtensions.AttackSensorsCompat(monster)) { ReNumPrefix.Replace(((Object)item).name, ""); AbstractConditionComp[] array = ReflectionExtension.GetFieldValue<AbstractConditionComp[]>((object)item, "_conditions") ?? Array.Empty<AbstractConditionComp>(); for (int i = 0; i < array.Length; i++) { string text2 = FormatCondition(array[i]); text = text + " if: " + text2 + "\n"; } } _ = monster.fsm.FindMappingState((States)3) is StealthEngaging; return text; } private static string FsmStateName(MappingState mappingState) { return ReCjk.Replace(((Object)mappingState).name, "").Trim(); } private static string FsmStateName(StateMachine<States> monster, States state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MappingState val = monster.FindMappingState(state); if (val != null) { return FsmStateName(val); } return ((object)(States)(ref state)).ToString(); } private static string MonsterName(MonsterBase monster) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) string text = ((object)(LocalizedString)(ref ((MonsterStat)(typeof(MonsterBase).GetField("_monsterStat") ?? typeof(MonsterBase).GetField("monsterStat")).GetValue(monster)).monsterName)).ToString(); if (text != "") { return text; } return StringExtensions.TrimEndMatches(StringExtensions.TrimStartMatches(StringExtensions.TrimStartMatches(((Object)monster).name, (ReadOnlySpan<char>)"StealthGameMonster_"), (ReadOnlySpan<char>)"TrapMonster_"), (ReadOnlySpan<char>)"(Clone)").ToString(); } private static string FormatCondition(AbstractConditionComp condition) { string arg = StringExtensions.TrimStartMatches(((Object)condition).name, (ReadOnlySpan<char>)"[Condition] ").ToString(); string text = ""; FlagBoolCondition val = (FlagBoolCondition)(object)((condition is FlagBoolCondition) ? condition : null); if (val == null) { GeneralCondition val2 = (GeneralCondition)(object)((condition is GeneralCondition) ? condition : null); if (val2 == null) { PlayerMovePredictCondition val3 = (PlayerMovePredictCondition)(object)((condition is PlayerMovePredictCondition) ? condition : null); if (val3 != null) { text += "Player"; if (val3.ParryDetect) { text += " Parry"; } if (val3.DodgeDetect) { text += " Dash"; } if (val3.JumpDetect) { text += " Jump"; } if (val3.InAirDetect) { text += " InAir"; } if (val3.AttackDetect) { text += " Attack"; } if (val3.ThirdAttackDetect) { text += " Third"; } if (val3.ChargeAttackDetect) { text += " Charged"; } if (val3.FooDetect) { text += " Foo"; } if (val3.ArrowDetect) { text += " Shoots"; } if ((double)val3.randomChance != 1.0) { text += $" at {val3.randomChance * 100f:0}%"; } } else { text += $" {((object)condition).GetType()}"; } } else { text += $" {val2}"; } } else { string arg2 = FormatVariable((AbstractVariable?)(object)val.flagBool); VariableBool flagBool = val.flagBool; text = $"{arg} bool flag {arg2} current {((flagBool != null) ? new bool?(flagBool.FlagValue) : null)}"; string text2 = text; VariableBool flagBool2 = val.flagBool; object obj; if (flagBool2 == null) { obj = null; } else { ScriptableDataBool boolFlag = flagBool2.boolFlag; obj = ((boolFlag != null) ? ((GameFlagBase)boolFlag).FinalSaveID : null); } text = text2 + " " + (string?)obj; text += $" {val.flagBool}"; } if (condition.FinalResultInverted) { text = "(inverted) " + text; } return "(" + (condition.FinalResult ? "true" : "false") + ") " + text; } private static string FormatVariable(AbstractVariable? variable) { if ((Object)(object)variable == (Object)null) { return "null"; } string text = StringExtensions.TrimEndMatches(StringExtensions.TrimStartMatches(((object)variable).ToString(), (ReadOnlySpan<char>)"[Variable] "), (ReadOnlySpan<char>)" (VariableBool)").ToString(); GameFlagBase finalData = variable.FinalData; return text + " " + ((finalData != null) ? finalData.GetSaveID : null); } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Constructor)] public sealed class SetsRequiredMembersAttribute : Attribute { } } namespace System.Runtime.CompilerServices { internal static class IsExternalInit { } public class RequiredMemberAttribute : Attribute { } public class CompilerFeatureRequiredAttribute : Attribute { public CompilerFeatureRequiredAttribute(string name) { } } } namespace DebugModPlus { [AttributeUsage(AttributeTargets.Method, Inherited = false)] [MeansImplicitUse] public class BindableMethod : Attribute { public string? Name; public KeyCode[]? DefaultKeybind; } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("DebugModPlus", "DebugModPlus", "1.10.0")] public class DebugModPlus : BaseUnityPlugin { public static DebugModPlus Instance; private DebugUI debugUI; private QuantumConsoleModule quantumConsoleModule = new QuantumConsoleModule(); private Harmony harmony; private InfotextModule InfotextModule; public HitboxModule HitboxModule; public SavestateModule SavestateModule; public SpeedrunTimerModule SpeedrunTimerModule; private FsmInspectorModule fsmInspectorModule = new FsmInspectorModule(); public GhostModule GhostModule; private ConfigEntry<KeyboardShortcut> configShortcutFsmPickerModifier; private Dictionary<KeyboardShortcut, string> configSavestateShortcutsCreate; private Dictionary<KeyboardShortcut, string> configSavestateShortcutsLoad; internal ConfigEntry<HitboxType> HitboxFilter; private bool initializedSuccessfully; internal static bool JustGainedFocus; private void HandleLog(string logString, string stackTrace, LogType type) { ToastManager.Toast((object)logString); } private void Awake() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: 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) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log.Init(((BaseUnityPlugin)this).Logger); Log.Info("Plugin DebugModPlus started loading..."); try { harmony = Harmony.CreateAndPatchAll(typeof(DebugModPlus).Assembly, (string)null); Type type = GameVersions.Select<Type>("d4c12f4d7e8442e79988244014fb92d2", typeof(PatchesSpeedrunPatch), typeof(PatchesCurrentPatch)); harmony.PatchAll(type); Log.Info($"Patched {harmony.GetPatchedMethods().Count()} methods..."); ConfigEntry<TimerMode> configTimerMode = ((BaseUnityPlugin)this).Config.Bind<TimerMode>("SpeedrunTimer", "Timer Mode", TimerMode.Triggers, (ConfigDescription)null); ConfigEntry<KeyboardShortcut> changeModeShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Cycle Timer Mode", default(KeyboardShortcut), (ConfigDescription)null); ConfigEntry<KeyboardShortcut> resetTimerShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Reset Timer", default(KeyboardShortcut), (ConfigDescription)null); ConfigEntry<KeyboardShortcut> pauseTimerShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Pause Timer", default(KeyboardShortcut), (ConfigDescription)null); ConfigEntry<KeyboardShortcut> setStartpointShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Set Startpoint", default(KeyboardShortcut), (ConfigDescription)null); ConfigEntry<KeyboardShortcut> setEndpointShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Set Endpoint", default(KeyboardShortcut), (ConfigDescription)null); ConfigEntry<KeyboardShortcut> clearCheckpointsShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Clear Checkpoints", default(KeyboardShortcut), (ConfigDescription)null); configShortcutFsmPickerModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Shortcuts", "FSM Picker Modifier", default(KeyboardShortcut), new ConfigDescription("When this key is pressed and you click on a sprite, it will try to open the FSM inspector for that object", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> configRecordGhost = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedrunTimer", "Record Ghost", false, (ConfigDescription)null); ConfigEntry<Color> ghostColor = ((BaseUnityPlugin)this).Config.Bind<Color>("SpeedrunTimer", "PB Ghost Color", new Color(1f, 0.8f, 0f, 0.5f), (ConfigDescription)null); ConfigEntry<bool> configPauseStopsTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedrunTimer", "Pause Timer Stops Speedrun Timer", false, (ConfigDescription)null); ConfigEntry<SavestateFilter> currentFilter = ((BaseUnityPlugin)this).Config.Bind<SavestateFilter>("Savestates", "Savestate filter", SavestateFilter.Flags | SavestateFilter.Player, (ConfigDescription)null); ConfigEntry<SavestateLoadMode> loadMode = ((BaseUnityPlugin)this).Config.Bind<SavestateLoadMode>("Savestates", "Savestate load mode", SavestateLoadMode.None, (ConfigDescription)null); ConfigEntry<InfotextModule.InfotextFilter> filter = ((BaseUnityPlugin)this).Config.Bind<InfotextModule.InfotextFilter>("Info Text Panel", "Show Info", global::DebugModPlus.Modules.InfotextModule.InfotextFilter.GameInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.BasicPlayerInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.AdvancedPlayerInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.RespawnInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.DamageInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.InteractableInfo, (ConfigDescription)null); HitboxFilter = ((BaseUnityPlugin)this).Config.Bind<HitboxType>("The rest", "Hitbox Filter", HitboxType.Default, (ConfigDescription)null); HitboxFilter.SettingChanged += delegate { HitboxModule.HitboxesVisible = true; }; configSavestateShortcutsCreate = new Dictionary<KeyboardShortcut, string>(); configSavestateShortcutsLoad = new Dictionary<KeyboardShortcut, string>(); InfotextModule = new InfotextModule(filter); SavestateModule = new SavestateModule(currentFilter, loadMode, ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Save", new KeyboardShortcut((KeyCode)270, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Load", new KeyboardShortcut((KeyCode)271, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Delete", new KeyboardShortcut((KeyCode)269, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Page next", new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Page prev", new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()), (ConfigDescription)null)); SpeedrunTimerModule = new SpeedrunTimerModule(configTimerMode, configRecordGhost, configPauseStopsTimer); GhostModule = new GhostModule(ghostColor); SavestateModule.SavestateLoaded += delegate { SpeedrunTimerModule.OnSavestateLoaded(); }; SavestateModule.SavestateCreated += delegate { SpeedrunTimerModule.OnSavestateCreated(); }; HitboxModule = new GameObject().AddComponent<HitboxModule>(); KeybindManager.Add((MonoBehaviour)(object)this, (Action)quantumConsoleModule.ToggleConsole, (KeyCode[])(object)new KeyCode[2] { (KeyCode)306, (KeyCode)46 }); KeybindManager.Add((MonoBehaviour)(object)this, (Action)ToggleSettings, (KeyCode[])(object)new KeyCode[2] { (KeyCode)306, (KeyCode)44 }); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.CycleTimerMode(); }, (Func<KeyboardShortcut>)(() => changeModeShortcut.Value)); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.ResetTimerUser(); }, (Func<KeyboardShortcut>)(() => resetTimerShortcut.Value)); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.PauseTimer(); }, (Func<KeyboardShortcut>)(() => pauseTimerShortcut.Value)); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.SetStartpoint(); }, (Func<KeyboardShortcut>)(() => setStartpointShortcut.Value)); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.SetEndpoint(); }, (Func<KeyboardShortcut>)(() => setEndpointShortcut.Value)); KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate { SpeedrunTimerModule.ClearCheckpoints(); }, (Func<KeyboardShortcut>)(() => clearCheckpointsShortcut.Value)); debugUI = ((Component)this).gameObject.AddComponent<DebugUI>(); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(FreecamModule)); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(TimeModule)); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(InfotextModule)); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(HitboxModule)); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(SavestateModule)); debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(CheatModule)); FlagLoggerModule.Awake(); RCGLifeCycle.DontDestroyForever(((Component)this).gameObject); RCGLifeCycle.DontDestroyForever(((Component)HitboxModule).gameObject); QuantumConsoleModule.Initialize(); Log.Info("Plugin DebugModPlus is loaded!"); initializedSuccessfully = true; } catch (Exception data) { Log.Error(data); } } private void ToggleSettings() { debugUI.settingsOpen = !debugUI.settingsOpen; _ = Player.i; } private void OnApplicationFocus(bool hasFocus) { JustGainedFocus |= hasFocus; } private void Update() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Invalid comparison between Unknown and I4 //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) if (!initializedSuccessfully) { return; } FreecamModule.Update(); MapTeleportModule.Update(); InfotextModule.Update(); SavestateModule.Update(); bool flag = false; foreach (KeyValuePair<KeyboardShortcut, string> item in configSavestateShortcutsCreate) { if (KeybindManager.CheckShortcutOnly(item.Key)) { SavestateModule.CreateSavestate(item.Value); flag = true; } } if (!flag) { foreach (KeyValuePair<KeyboardShortcut, string> item2 in configSavestateShortcutsLoad) { if (KeybindManager.CheckShortcutOnly(item2.Key)) { SavestateModule.LoadSavestateAt(item2.Value); } } } Player i = Player.i; PlayerInputStateType? val = ((i != null) ? new PlayerInputStateType?(i.playerInput.fsm.State) : null); bool flag2 = !val.HasValue || (int)val.GetValueOrDefault() != 1; KeyboardShortcut value = configShortcutFsmPickerModifier.Value; if (((KeyboardShortcut)(ref value)).IsPressed() && Input.GetMouseButtonDown(0)) { fsmInspectorModule.Objects.Clear(); if (flag2) { Cursor.visible = true; TryPickFsm(); } } JustGainedFocus = false; } private void TryPickFsm() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) fsmInspectorModule.Objects.Clear(); try { Camera theRealSceneCamera = SingletonBehaviour<CameraManager>.Instance.cameraCore.theRealSceneCamera; Vector3 worldPosition = theRealSceneCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f - ((Component)theRealSceneCamera).transform.position.z)); worldPosition.z = 0f; GameObject val = (from x in ((IEnumerable<GameObject>)PickVisible(worldPosition)).Select((Func<GameObject, GameObject>)delegate(GameObject sprite) { StateMachineOwner componentInParent = sprite.GetComponentInParent<StateMachineOwner>(); object obj = ((componentInParent != null) ? ((Component)componentInParent).gameObject : null); if (obj == null) { FSMStateMachineRunner componentInParent2 = sprite.GetComponentInParent<FSMStateMachineRunner>(); if (componentInParent2 == null) { return null; } obj = ((Component)componentInParent2).gameObject; } return (GameObject)obj; }) where Object.op_Implicit((Object)(object)x) select x).Distinct().FirstOrDefault(); if (Object.op_Implicit((Object)(object)val)) { fsmInspectorModule.Objects.Add(val); } else { ToastManager.Toast((object)"No state machine found at cursor"); } } catch (Exception ex) { ToastManager.Toast((object)ex); } } private List<GameObject> PickVisible(Vector3 worldPosition) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return (from x in (from t in (from renderer in Object.FindObjectsOfType<SpriteRenderer>() select (((Component)renderer).gameObject, ((Renderer)renderer).bounds)).Concat(from renderer in Object.FindObjectsOfType<ParticleSystemRenderer>() select (((Component)renderer).gameObject, ((Renderer)renderer).bounds)) where ((Bounds)(ref t.bounds)).Contains(worldPosition) select t).Where<(GameObject, Bounds)>(delegate((GameObject gameObject, Bounds bounds) t) { string text = ((Object)t.gameObject.gameObject).name.ToLower(); Transform parent = t.gameObject.gameObject.transform.parent; string text2 = ((parent != null) ? ((Object)parent).name : null) ?? ""; return !text.Contains("light") && !text.Contains("fade") && !text.Contains("glow") && !text.Contains("attack") && !text2.Contains("Vibe") && !text2.Contains("Skin"); }) select x.gameObject).ToList(); } private void LateUpdate() { if (!initializedSuccessfully) { return; } try { GhostModule.LateUpdate(); SpeedrunTimerModule.LateUpdate(); } catch (Exception data) { Log.Error(data); } } private void OnGUI() { if (!initializedSuccessfully) { return; } try { SpeedrunTimerModule.OnGui(); } catch (Exception arg) { Log.Error($"Error in SpeedrunTimerModule: {arg}"); } try { fsmInspectorModule.OnGui(); } catch (Exception arg2) { Log.Error($"Error in fsm inspector module: {arg2}"); } try { SavestateModule.OnGui(); } catch (Exception arg3) { Log.Error($"Error in SavestateModule: {arg3}"); } try { InfotextModule.OnGui(); } catch (Exception arg4) { Log.Error($"Error in InfotextModule: {arg4}"); } } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Application.logMessageReceived -= new LogCallback(HandleLog); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } GhostModule?.Unload(); SpeedrunTimerModule?.Destroy(); InfotextModule?.Destroy(); HitboxModule hitboxModule = HitboxModule; if (Object.op_Implicit((Object)(object)((hitboxModule != null) ? ((Component)hitboxModule).gameObject : null))) { Object.Destroy((Object)(object)((Component)HitboxModule).gameObject); } Log.Info("Plugin DebugModPlus unloaded\n\n"); } } [PublicAPI] public class DebugSave { public const int DebugSaveIndex = 100; public static void LoadDebugSave() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) SingletonBehaviour<SaveManager>.Instance.LoadSaveAtSlot(100); SingletonBehaviour<ApplicationUIGroupManager>.Instance.ClearAll(); RuntimeInitHandler.LoadCore(); if (!GameVersions.IsVersion("d4c12f4d7e8442e79988244014fb92d2")) { typeof(GameConfig).GetMethod("InstantiateGameCore").Invoke(ScriptableObjectSingleton<GameConfig>.Instance, Array.Empty<object>()); } } } internal class DebugActionToggle { public bool Value; public required Action<bool> OnChange; } internal class DebugAction { public required Action OnChange; } public class DebugUI : MonoBehaviour { public bool settingsOpen; private GUIStyle? styleButton; private GUIStyle? styleToggle; private Dictionary<string, DebugActionToggle> toggles = new Dictionary<string, DebugActionToggle>(); private Dictionary<string, DebugAction> actions = new Dictionary<string, DebugAction>(); private void Awake() { toggles.Clear(); } public void AddBindableMethods(ConfigFile config, Type ty) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) MethodInfo[] methods = ty.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { BindableMethod customAttribute = methodInfo.GetCustomAttribute<BindableMethod>(); if (customAttribute != null) { string text = customAttribute.Name ?? methodInfo.Name; Action action = (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); string text2 = new string(Array.FindAll(text.ToCharArray(), char.IsLetterOrDigit)); ConfigEntry<KeyboardShortcut> keyboardShortcut = config.Bind<KeyboardShortcut>("Shortcuts", text2, (customAttribute.DefaultKeybind != null) ? new KeyboardShortcut(customAttribute.DefaultKeybind[^1], customAttribute.DefaultKeybind[..^1]) : default(KeyboardShortcut), (ConfigDescription)null); actions.Add(text, new DebugAction { OnChange = action }); KeybindManager.Add((MonoBehaviour)(object)this, action, (Func<KeyboardShortcut>)(() => keyboardShortcut.Value)); } } } public void AddToggle(string actionName, Action<bool> onChange, bool defaultValue = false) { toggles.Add(actionName, new DebugActionToggle { Value = defaultValue, OnChange = onChange }); } private void OnGUI() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown if (!settingsOpen) { return; } RCGInput.SetCursorVisible(true); if (styleButton == null) { styleButton = new GUIStyle(GUI.skin.box) { alignment = (TextAnchor)5, padding = new RectOffset(20, 20, 20, 20), fontSize = 20 }; } if (styleToggle == null) { styleToggle = new GUIStyle(GUI.skin.toggle) { fontSize = 20 }; } GUILayout.BeginArea(new Rect(20f, 20f, (float)(Screen.width - 40), (float)(Screen.height - 40))); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); string key; foreach (KeyValuePair<string, DebugActionToggle> toggle in toggles) { toggle.Deconstruct(out key, out var value); string arg = key; DebugActionToggle debugActionToggle = value; if (GUILayout.Button($"{arg}: {debugActionToggle.Value}", styleButton, Array.Empty<GUILayoutOption>())) { debugActionToggle.Value = !debugActionToggle.Value; debugActionToggle.OnChange(debugActionToggle.Value); ToastManager.Toast((object)$"change {arg} to {debugActionToggle.Value}"); } } foreach (KeyValuePair<string, DebugAction> action in actions) { action.Deconstruct(out key, out var value2); object obj = key; DebugAction debugAction = value2; if (obj == null) { obj = ""; } if (GUILayout.Button((string)obj, styleButton, Array.Empty<GUILayoutOption>())) { debugAction.OnChange(); } } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); GUILayout.EndArea(); } } [HarmonyPatch] public class FastLoads { public static bool Enabled { get { if (!FreecamModule.FreecamActive) { return SavestateModule.IsLoadingSavestate; } return true; } } [HarmonyPatch(typeof(GameCore), "FadeOutBlack")] [HarmonyPrefix] private static void FadeOutBlack(ref float fadeTime, ref float delayTime) { if (Enabled) { fadeTime = 0f; delayTime = 0f; } } [HarmonyPatch(typeof(UIExtension), "AddUITask")] [HarmonyPrefix] private static void AddUiTask(MonoBehaviour mb, Action action, ref float delay) { if (Enabled) { delay = 0f; } } } public class GameInfo { private static float statsLastHP = 0f; private static float statsLastIntDmg = 0f; private static Vector2 statsLastPos = Vector2.zero; private static MovingAverage averagePlayerX = new MovingAverage(); private static MovingAverage averagePlayerY = new MovingAverage(); private float playerLastHP = statsLastHP; private float playerLastIntDmg = statsLastIntDmg; public string? ErrorText; public string GameLevel = ""; public string CoreState = ""; public string Cutscene = ""; public float PlayerHp; public float PlayerLostHp; public float PlayerMaxHp; public float PlayerIntNewDmg; public float PlayerIntDmg; public Vector2 PlayerPos; public Vector2 PlayerSafePos; public Vector2 SceneRespawn; public Vector2 PlayerRespawn; public Vector2 PlayerSpeed; public Vector2 PlayerAvgSpeed; public string playerState = ""; public string PlayerJumpState = ""; public string PlayerJumpTimer = ""; public bool PlayerRope; public float PlayerRopeX; public bool PlayerWall; public bool PlayerLedge; public bool PlayerKicked; public bool DebugAutoHeal; public bool DebugInvincibility; public float EnemyHP; public float CummHPDmg; public float CummIntDmg; public int FruitCount; public int Fruit; public int GreaterFruit; public int TwinFruit; public float AttackDamage; public float FooDamage; public List<string> Interactables = new List<string>(); public GameInfo() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Invalid comparison between Unknown and I4 //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Invalid comparison between Unknown and I4 //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Invalid comparison between Unknown and I4 //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) try { if (!SingletonBehaviour<GameCore>.IsAvailable()) { return; } GameCore instance = SingletonBehaviour<GameCore>.Instance; Player player = instance.player; if (player == null) { Log.Error("Error during InfoText collection: player or core is null"); return; } Scene activeScene = SceneManager.GetActiveScene(); GameLevel = ((Scene)(ref activeScene)).name; GameCoreState currentCoreState = instance.currentCoreState; CoreState = ((object)(GameCoreState)(ref currentCoreState)).ToString(); if (Object.op_Implicit((Object)(object)instance.currentCutScene)) { Cutscene = ((Object)instance.currentCutScene).name; } PlayerHealth val = (PlayerHealth)player.GetHealth; if (val != null) { PlayerMaxHp = ((Health)val).maxHealth.Value; PlayerHp = val.CurrentHealthValue; if (PlayerHp != statsLastHP) { PlayerLostHp = PlayerHp - statsLastHP; statsLastHP = PlayerHp; } PlayerIntDmg = val.CurrentInternalInjury; if (PlayerIntDmg != playerLastIntDmg) { PlayerIntNewDmg = PlayerIntDmg - playerLastIntDmg; } } if (Object.op_Implicit((Object)(object)instance.gameLevel)) { (SpawnType, Vector3) nearestSpawnPoint = SingletonBehaviour<GameCore>.Instance.gameLevel.GetNearestSpawnPoint(); SpawnType item2 = nearestSpawnPoint.Item1; PlayerPos = Vector2.op_Implicit(((Component)player).transform.position); PlayerSafePos = Vector2.op_Implicit(player.lastSafeGroundPosition); PlayerRespawn = (SceneRespawn = Vector2.op_Implicit(nearestSpawnPoint.Item2)); if ((int)item2 == 3) { PlayerRespawn = PlayerSafePos; } else if (player.SafeGroundRecorder.LastSafeGroundPositionList.Count > 0 && ((int)item2 == 1 || (int)item2 == 2)) { PlayerRespawn = PlayerSafePos; } else { Vector3 position = ((Component)SingletonBehaviour<CameraManager>.Instance.cameraCore.theRealSceneCamera).transform.position; float num = Vector2.Distance(Vector2.op_Implicit(position), SceneRespawn); if (Vector2.Distance(Vector2.op_Implicit(position), PlayerSafePos) < num) { PlayerRespawn = PlayerSafePos; } } } PlayerSpeed = ((Actor)player).FinalVelocity; averagePlayerX.Sample((long)PlayerSpeed.x); averagePlayerY.Sample((long)PlayerSpeed.y); PlayerAvgSpeed = new Vector2(averagePlayerX.GetAverageFloat, averagePlayerY.GetAverageFloat); playerState = ((Object)player.CurrentState).name; PlayerRope = Object.op_Implicit((Object)(object)player.touchingRope); if (PlayerRope) { PlayerRopeX = ((Component)player.touchingRope).transform.position.x; } PlayerWall = player.isOnWall; PlayerLedge = player.isOnLedge; PlayerKicked = player.kicked; PlayerJumpState jumpState = player.jumpState; PlayerJumpState = ((object)(PlayerJumpState)(ref jumpState)).ToString(); if ((int)player.jumpState != 0) { float currentVarJumpTimer = player.currentVarJumpTimer; PlayerJumpTimer = ((currentVarJumpTimer > 0f) ? currentVarJumpTimer.ToString("0.00") : ""); } Fruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item) { ItemData val4 = (ItemData)(object)((item is ItemData) ? item : null); return val4 != null && ((GameFlagDescriptable)val4).Title == "Tao Fruit"; })).ownNum).CurrentValue; GreaterFruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item) { ItemData val3 = (ItemData)(object)((item is ItemData) ? item : null); return val3 != null && ((GameFlagDescriptable)val3).Title == "Greater Tao Fruit"; })).ownNum).CurrentValue; TwinFruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item) { ItemData val2 = (ItemData)(object)((item is ItemData) ? item : null); return val2 != null && ((GameFlagDescriptable)val2).Title == "Twin Tao Fruit"; })).ownNum).CurrentValue; FruitCount = Fruit + GreaterFruit + TwinFruit; AttackDamage = player.normalAttackDealer.FinalValue; FooDamage = player.fooEffectDealer.FinalValue; InteractableArea currentInteractableArea = player.interactableFinder.CurrentInteractableArea; if (currentInteractableArea == null) { return; } foreach (AbstractInteraction validInteraction in currentInteractableArea.ValidInteractions) { Interactables.Add(((Object)((Component)((Component)validInteraction).transform.parent).transform.parent).name); } } catch (Exception ex) { ErrorText = ex.ToString(); Log.Error(ErrorText); } } } internal static class Log { private static ManualLogSource logSource; internal static void Init(ManualLogSource logSource) { Log.logSource = logSource; } internal static void Debug(object data) { logSource.LogDebug(data); } internal static void Error(object data) { logSource.LogError(data); } internal static void Fatal(object data) { logSource.LogFatal(data); } internal static void Info(object data) { logSource.LogInfo(data); } internal static void Message(object data) { logSource.LogMessage(data); } internal static void Warning(object data) { logSource.LogWarning(data); } } public static class PatchesSpeedrunPatch { [HarmonyPatch(typeof(GameCore), "FadeToBlack")] [HarmonyPrefix] private static void FadeToBlack(ref float fadeTime) { if (FastLoads.Enabled) { fadeTime = 0f; } } [HarmonyPatch(typeof(GameCore), "ChangeScene", new Type[] { typeof(ChangeSceneData), typeof(bool), typeof(bool) })] [HarmonyPrefix] private static void ChangeScene(ref ChangeSceneData changeSceneData, ref bool showTip, bool captureLastImage) { DebugModPlus.Instance.SpeedrunTimerModule.OnLevelChange(); if (FastLoads.Enabled) { showTip = false; } } } public static class PatchesCurrentPatch { [HarmonyPatch(typeof(GameCore), "FadeToBlack", new Type[] { typeof(float), typeof(float) })] [HarmonyPatch(typeof(GameCore), "FadeToBlack", new Type[] { typeof(float), typeof(UnityAction), typeof(float) })] [HarmonyPrefix] private static void FadeToBlack(ref float fadeTime) { if (FastLoads.Enabled) { fadeTime = 0f; } } [HarmonyPatch(typeof(GameCore), "ChangeScene", new Type[] { typeof(ChangeSceneData), typeof(bool), typeof(bool), typeof(float) })] [HarmonyPrefix] private static void ChangeScene(ref ChangeSceneData changeSceneData, ref bool showTip, bool captureLastImage, ref float delayTime) { DebugModPlus.Instance.SpeedrunTimerModule.OnLevelChange(); if (FastLoads.Enabled) { delayTime = 0f; showTip = false; } } } public class AnimatorSnapshot { public required int StateHash; public required float NormalizedTime; public required Dictionary<int, float> ParamsFloat; public required Dictionary<int, int> ParamsInt; public required Dictionary<int, bool> ParamsBool; public static AnimatorSnapshot Snapshot(Animator animator) { //IL_0002: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected I4, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0); AnimatorControllerParameter[] parameters = animator.parameters; Dictionary<int, float> dictionary = new Dictionary<int, float>(); Dictionary<int, bool> dictionary2 = new Dictionary<int, bool>(); Dictionary<int, int> dictionary3 = new Dictionary<int, int>(); AnimatorControllerParameter[] array = parameters; foreach (AnimatorControllerParameter val in array) { AnimatorControllerParameterType type = val.type; switch (type - 1) { default: if ((int)type == 9) { continue; } break; case 0: dictionary[val.nameHash] = animator.GetFloat(val.nameHash); continue; case 3: dictionary2[val.nameHash] = animator.GetBool(val.nameHash); continue; case 2: dictionary3[val.nameHash] = animator.GetInteger(val.nameHash); continue; case 1: break; } ToastManager.Toast((object)$"Unsnapshotted param {val.type}"); } return new AnimatorSnapshot { StateHash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash, NormalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime, ParamsFloat = dictionary, ParamsInt = dictionary3, ParamsBool = dictionary2 }; } public void Restore(Animator animator) { if ((Object)(object)animator == (Object)null) { return; } if (((Object)animator).name == "Animator") { Transform val = ((Component)animator).transform; while (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.SetActive(true); val = val.parent; } } animator.Play(StateHash, 0, NormalizedTime); animator.Update(0f); foreach (KeyValuePair<int, float> item in ParamsFloat) { animator.SetFloat(item.Key, item.Value); } foreach (KeyValuePair<int, int> item2 in ParamsInt) { animator.SetInteger(item2.Key, item2.Value); } foreach (KeyValuePair<int, bool> item3 in ParamsBool) { animator.SetBool(item3.Key, item3.Value); } } } public class Savestate { private class ForceSerializeResolver : DefaultContractResolver { public List<Type> ForceSerializePropertiesOf = new List<Type>(); protected override List<MemberInfo> GetSerializableMembers(Type objectType) { if (ForceSerializePropertiesOf.Contains(objectType)) { return objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Cast<MemberInfo>().ToList(); } return ((DefaultContractResolver)this).GetSerializableMembers(objectType); } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { return ((DefaultContractResolver)this).CreateProperty(member, (MemberSerialization)2); } } public string? Scene; public Vector3? PlayerPosition; public string? LastTeleportId; public List<ComponentSnapshot>? MonobehaviourSnapshots; public List<GameObjectSnapshot>? GameObjectSnapshots; public List<MonsterLoveFsmSnapshot>? FsmSnapshots; public List<GeneralFsmSnapshot>? GeneralFsmSnapshots; public List<ReferenceFixups>? ReferenceFixups; public JObject? Flags; public State? RandomState; private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings { Formatting = (Formatting)1, NullValueHandling = (NullValueHandling)1, ContractResolver = (IContractResolver)(object)new ForceSerializeResolver { ForceSerializePropertiesOf = new List<Type>(1) { typeof(State) } }, Converters = new List<JsonConverter>(1) { (JsonConverter)(object)new Vector3Converter() } }; public void SerializeTo(StreamWriter writer) { JsonSerializer.Create(jsonSettings).Serialize((TextWriter)writer, (object)this); } public static Savestate DeserializeFrom(StreamReader reader) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown JsonTextReader val = new JsonTextReader((TextReader)reader); return JsonSerializer.Create(jsonSettings).Deserialize<Savestate>((JsonReader)(object)val) ?? throw new Exception("Failed to deserialize savestate"); } public string Serialize() { return JsonConvert.SerializeObject((object)this, (Formatting)1); } public static Savestate Deserialize(string data) { return JsonConvert.DeserializeObject<Savestate>(data) ?? throw new Exception("Failed to deserialize savestate"); } } public record GameObjectData(bool Active); public class GameObjectSnapshot { public required string Path; public required GameObjectData Data; public static GameObjectSnapshot Of(GameObject go) { return new GameObjectSnapshot { Path = ObjectUtils.ObjectPath(go), Data = new GameObjectData(go.activeSelf) }; } public bool Restore() { GameObject val = ObjectUtils.LookupPath(Path); if (!Object.op_Implicit((Object)(object)val)) { Log.Error("Savestate stored state on " + Path + ", which does not exist at load time"); return false; } val.SetActive(Data.Active); return true; } } public class ComponentSnapshot { public required string Path; public required JToken Data; public static ComponentSnapshot Of(Component mb) { return new ComponentSnapshot { Path = ObjectUtils.ObjectComponentPath(mb), Data = SnapshotSerializer.Snapshot(mb) }; } public bool Restore() { Component val = ObjectUtils.LookupObjectComponentPath(Path); if (!Object.op_Implicit((Object)(object)val)) { Log.Error("Savestate stored state on " + Path + ", which does not exist at load time"); return false; } SnapshotSerializer.Populate(val, Data); return true; } } public class GeneralFsmSnapshot { public required string Path; public required string CurrentState; public static GeneralFsmSnapshot Of(StateMachineOwner owner) { return new GeneralFsmSnapshot { Path = ObjectUtils.ObjectPath(((Component)owner).gameObject), CurrentState = ((Object)((StateMachineContext<GeneralState, GeneralState>)(object)owner.FsmContext).fsm.State).name }; } } public class MonsterLoveFsmSnapshot { public required string Path; public required object CurrentState; public static MonsterLoveFsmSnapshot Of(IStateMachine machine) { return new MonsterLoveFsmSnapshot { Path = ObjectUtils.ObjectPath(((Component)machine.Component).gameObject), CurrentState = machine.CurrentStateMap.stateObj }; } } public record ReferenceFixupField(string Field, string? Reference); public class ReferenceFixups { public required string Path; public required List<ReferenceFixupField> Fields; public static ReferenceFixups Of(MonoBehaviour mb, List<ReferenceFixupField> fixups) { return new ReferenceFixups { Path = ObjectUtils.ObjectComponentPath((Component)(object)mb), Fields = fixups }; } } public static class SnapshotSerializer { private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { ReferenceLoopHandling = (ReferenceLoopHandling)0, Error = delegate(object _, ErrorEventArgs args) { args.ErrorContext.Handled = true; Log.Error($"Serialization error while creating snapshot: {args.CurrentObject?.GetType()}: {args.ErrorContext.Path}: {args.ErrorContext.Error.Message}"); }, ContractResolver = (IContractResolver)(object)resolver, Converters = new List<JsonConverter> { (JsonConverter)(object)new Vector2Converter(), (JsonConverter)(object)new Vector3Converter(), (JsonConverter)(object)new Vector4Converter(), (JsonConverter)(object)new QuatConverter(), (JsonConverter)(object)new ColorConverter(), (JsonConverter)(object)new Color32Converter(), (JsonConverter)(object)new AnimatorConverter(), (JsonConverter)new StringEnumConverter() } }; private static CustomizableContractResolver resolver { get { CustomizableContractResolver customizableContractResolver = new CustomizableContractResolver(); customizableContractResolver.ContainerTypesToIgnore = new Type[3] { typeof(MonoBehaviour), typeof(Component), typeof(Object) }; customizableContractResolver.FieldTypesToIgnore = new Type[48] { typeof(PoolObject), typeof(MonoBehaviour), typeof(Camera), typeof(GameObject), typeof(UnityEventBase), typeof(Action), typeof(Delegate), typeof(FxPlayer), typeof(StateEvents), typeof(IEffectOwner), typeof(PositionConstraint), typeof(PathArea), typeof(IEffectHitHandler), typeof(ICooldownEffectReceiver), typeof(PathToAreaFinder), typeof(Value), typeof(Sprite), typeof(Tilemap), typeof(LineRenderer), typeof(Color), typeof(VelocityModifierParam), typeof(ParticleSystem), typeof(RopeSegment), typeof(AnimationCurve), typeof(MultiSpriteEffectController), typeof(AnimationClip), typeof(IActiveOverrider), typeof(CullingObserver), typeof(Rect), typeof(DelayTask), typeof(Tween), typeof(RenderTexture), typeof(Texture2D), typeof(Texture3D), typeof(Transform), typeof(SpriteRenderer), typeof(LayerMask), typeof(Collider2D), typeof(AbilityWrapper), typeof(EffectHitData), typeof(DelayPositionData), typeof(IStateMachine), typeof(RuntimeConditionVote), typeof(ScriptableObject), typeof(StatData), typeof(CharacterStat), typeof(StatModifier), typeof(MapTileData) }; customizableContractResolver.ExactFieldTypesToIgnore = new Type[4] { typeof(IResetter), typeof(ILevelDestroy), typeof(ILevelStart), typeof(Component) }; customizableContractResolver.FieldAllowlist = new Dictionary<Type, string[]> { { typeof(Transform), new string[3] { "localPosition", "localRotation", "localScale" } }, { typeof(Rigidbody2D), new string[1] { "position" } }, { typeof(ProCamera2D), new string[4] { "_cameraTargetHorizontalPositionSmoothed", "_cameraTargetVerticalPositionSmoothed", "_previousCameraTargetHorizontalPositionSmoothed", "_previousCameraTargetVerticalPositionSmoothed" } } }; customizableContractResolver.FieldDenylist = new Dictionary<Type, string[]> { { typeof(StealthGameMonster), new string[1] { "boxColliderSizes" } }, { typeof(FlyingMonster), new string[1] { "boxColliderSizes" } }, { typeof(MonsterCore), new string[1] { "AnimationSpeed" } } }; return customizableContractResolver; } } public static void SnapshotRecursive(MonoBehaviour origin, List<ComponentSnapshot> saved, HashSet<Component> seen, int? maxDepth = null, int minDepth = 0, bool onlyDescendants = true) { MonobehaviourTracing.TraceReferencedMonobehaviours((Component)(object)origin, saved, seen, (Component?)(object)(onlyDescendants ? origin : null), 0, maxDepth, minDepth); } public static JToken Snapshot(object obj) { return JToken.FromObject(obj, JsonSerializer.Create(Settings)); } public static string SnapshotToString(object? obj) { return JsonConvert.SerializeObject(obj, (Formatting)1, Settings); } public static void Populate(object target, string json) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown JsonReader val = (JsonReader)new JsonTextReader((TextReader)new StringReader(json)); try { JsonSerializer.Create(Settings).Populate(val, target); } finally { ((IDisposable)val)?.Dispose(); } } public static void Populate(object target, JToken json) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown JsonSerializer val = JsonSerializer.Create(Settings); JsonReader val2 = (JsonReader)new JTokenReader(json); try { val.Populate(val2, target); } finally { ((IDisposable)val2)?.Dispose(); } } internal static void RemoveNullFields(JToken token, params string[] fields) { //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) JContainer val = (JContainer)(object)((token is JContainer) ? token : null); if (val == null) { return; } List<JToken> list = new List<JToken>(); foreach (JToken item in ((JToken)val).Children()) { JProperty val2 = (JProperty)(object)((item is JProperty) ? item : null); if (val2 != null && fields.Contains(val2.Name) && val2.Value.ToObject<object>() == null) { list.Add(item); } RemoveNullFields(item, fields); } foreach (JToken item2 in list) { item2.Remove(); } } } public static class UiUtils { public static Texture2D GetColorTexture(Color color) { //IL_0002: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } } internal sealed class MovingAverage { private readonly int windowSize; private readonly Queue<long> samples; private long sampleAccumulator; public long GetAverage => sampleAccumulator / samples.Count; public float GetAverageFloat => (float)sampleAccumulator / (float)samples.Count; public MovingAverage(int windowSize = 30) { this.windowSize = windowSize; samples = new Queue<long>(this.windowSize + 1); } public void Clear() { sampleAccumulator = 0L; samples.Clear(); } public void Sample(long newSample) { sampleAccumulator += newSample; samples.Enqueue(newSample); if (samples.Count > windowSize) { sampleAccumulator -= samples.Dequeue(); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "DebugModPlus"; public const string PLUGIN_NAME = "DebugModPlus"; public const string PLUGIN_VERSION = "1.10.0"; } } namespace DebugModPlus.Utils { public static class Extensions { public static IEnumerable<AttackSensor> AttackSensorsCompat(this MonsterBase monsterBase) { FieldInfo field = typeof(MonsterBase).GetField("attackSensors", BindingFlags.Instance | BindingFlags.Public); if (field != null) { return (List<AttackSensor>)field.GetValue(monsterBase); } return (AttackSensor[])typeof(MonsterBase).GetField("_attackSensors", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(monsterBase); } } public static class StateMachineExtensions { private static FieldRef<FSMStateMachineRunner, List<IStateMachine>> stateMachineRunnerStateMachineList = AccessTools.FieldRefAccess<FSMStateMachineRunner, List<IStateMachine>>("stateMachineList"); private static FieldRef<AbstractStateTransition, AbstractConditionComp[]> stateTransitionConditions = AccessTools.FieldRefAccess<AbstractStateTransition, AbstractConditionComp[]>("conditions"); public static AbstractConditionComp[] Conditions(this AbstractStateTransition transition) { return stateTransitionConditions.Invoke(transition); } public static List<IStateMachine> GetMachines(this FSMStateMachineRunner runner) { return stateMachineRunnerStateMachineList.Invoke(runner); } public static IEnumerable<(object, MappingState)> GetStates(this IStateMachine machine) { return ReflectionExtension.GetFieldValue<IList>(ReflectionExtension.GetFieldValue<object>((object)machine, "_stateMapping"), "mappingList").Cast<object>().Select(delegate(object stateObj) { object fieldValue = ReflectionExtension.GetFieldValue<object>(stateObj, "state"); MappingState fieldValue2 = ReflectionExtension.GetFieldValue<MappingState>(stateObj, "stateBehavior"); return (fieldValue, fieldValue2); }); } } } namespace DebugModPlus.Savestates { [PublicAPI] public class CustomizableContractResolver : DefaultContractResolver { public BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public BindingFlags PropertyBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public Dictionary<Type, string[]> FieldAllowlist = new Dictionary<Type, string[]>(); public Dictionary<Type, string[]> FieldDenylist = new Dictionary<Type, string[]>(); public Type[] ContainerTypesToIgnore = Array.Empty<Type>(); public Type[] FieldTypesToIgnore = Array.Empty<Type>(); public Type[] ExactFieldTypesToIgnore = Array.Empty<Type>(); protected override List<MemberInfo> GetSerializableMembers(Type objectType) { List<MemberInfo> list = new List<MemberInfo>(); Type ty = objectType; while (ty != typeof(object) && ty != null) { Type key = (ty.IsGenericType ? ty.GetGenericTypeDefinition() : ty); if (FieldAllowlist.TryGetValue(key, out string[] value)) { list.AddRange(value.Select(delegate(string fieldName) { object obj = ((object)ty.GetField(fieldName, FieldBindingFlags | BindingFlags.DeclaredOnly)) ?? ((object)ty.GetProperty(fieldName, PropertyBindingFlags | BindingFlags.DeclaredOnly)); if ((MemberInfo?)obj == null) { Log.Error($"Field '{fieldName}' in allowlist of '{ty}' does not exist!"); } return (MemberInfo)obj; }).Cast<MemberInfo>()); } else { list.AddRange(from field in ty.GetFields(FieldBindingFlags | BindingFlags.DeclaredOnly) where field.GetCustomAttribute<CompilerGeneratedAttribute>() == null select field); list.AddRange(ty.GetProperties(PropertyBindingFlags | BindingFlags.DeclaredOnly).Where(delegate(PropertyInfo prop) { if (prop.CanWrite && prop.CanRead) { MethodInfo getMethod = prop.GetGetMethod(); if ((object)getMethod == null || !getMethod.IsVirtual) { return ((MemberInfo)prop).GetCustomAttribute<NativePropertyAttribute>() != null; } return true; } return false; })); } ty = ty.BaseType; } if (FieldDenylist.TryGetValue(objectType, out string[] denyList)) { list.RemoveAll((MemberInfo field) => denyList.Contains(field.Name)); } return list; } protected override JsonContract CreateContract(Type objectType) { if (objectType == typeof(Transform)) { return (JsonContract)(object)((DefaultContractResolver)this).CreateObjectContract(objectType); } return ((DefaultContractResolver)this).CreateContract(objectType); } private bool IgnorePropertyType(Type? type) { Type type2 = type; if (!Array.Exists(ExactFieldTypesToIgnore, (Type x) => x == type2)) { return Array.Exists(FieldTypesToIgnore, (Type x) => x.IsAssignableFrom(type2)); } return true; } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty val = ((DefaultContractResolver)this).CreateProperty(member, (MemberSerialization)2); val.Ignored = false; bool shouldSerialize = true; Type propertyType = val.PropertyType; if (propertyType == null) { return val; } shouldSerialize &= !IgnorePropertyType(propertyType); if (propertyType.IsArray) { shouldSerialize &= !IgnorePropertyType(propertyType.GetElementType()); } if (propertyType.IsGenericType) { if (propertyType.GetGenericTypeDefinition() == typeof(List<>)) { shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[0]); val.ObjectCreationHandling = (ObjectCreationHandling)2; } if (propertyType.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { Type[] genericArguments = propertyType.GetGenericArguments(); shouldSerialize &= genericArguments[0].IsPrimitive || genericArguments[0] == typeof(string); shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[1]); } if (propertyType.GetGenericTypeDefinition() == typeof(HashSet<>)) { shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[0]); } } if (ContainerTypesToIgnore.Contains<Type>(member.DeclaringType)) { shouldSerialize = false; } val.ShouldSerialize = (object _) => shouldSerialize; return val; } } public class MappingConverter<T, TU> : JsonConverter<T> { [CompilerGenerated] private Func<T, TU> <func>P; public MappingConverter(Func<T, TU> func) { <func>P = func; base..ctor(); } public override void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer) { serializer.Serialize(writer, (value == null) ? "null" : ((object)<func>P(value))); } public override T ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); } } public abstract class NullableJsonConverter<T> : JsonConverter { public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); } else { WriteJson(writer, (T)value, serializer); } } protected abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer); public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (existingValue != null && !(existingValue is T)) { throw new JsonSerializationException($"Converter cannot read JSON with the specified existing value. {typeof(T)} is required."); } return ReadJson(reader, objectType, (existingValue == null) ? default(T) : ((T)existingValue), existingValue != null, serializer); } protected abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer); public sealed override bool CanConvert(Type objectType) { Type c = Nullable.GetUnderlyingType(objectType) ?? objectType; return typeof(T).IsAssignableFrom(c); } } public abstract class NullableJsonConverter : JsonConverter { public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); } else { WriteJsonInner(writer, value, serializer); } } protected abstract void WriteJsonInner(JsonWriter writer, object value, JsonSerializer serializer); public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (existingValue != null) { throw new JsonSerializationException("Converter cannot read JSON with the specified existing value."); } return ReadJsonInner(reader, objectType, existingValue, serializer); } protected abstract object? ReadJsonInner(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer); protected abstract bool CanConvertInner(Type objectType); public sealed override bool CanConvert(Type objectType) { Type objectType2 = Nullable.GetUnderlyingType(objectType) ?? objectType; return CanConvertInner(objectType2); } } public class EnumConverter : NullableJsonConverter { public static string EnumToString(object value) { string? fullName = value.GetType().FullName; string name = Enum.GetName(value.GetType(), value); return fullName + "." + name; } protected override void WriteJsonInner(JsonWriter writer, object? value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); } else { writer.WriteValue(EnumToString(value)); } } protected override object ReadJsonInner(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } protected override bool CanConvertInner(Type objectType) { return objectType.IsEnum; } } public static class FlagLogic { public static void LoadFlags(JObject newFlags, GameFlagCollection allFlags) { foreach (KeyValuePair<string, GameFlagBase> item in allFlags.flagDict) { item.Deconstruct(out var key, out var value); string text = key; GameFlagBase val = value; JToken obj = newFlags[text]; JObject val2 = (JObject)(object)((obj is JObject) ? obj : null); if (val2 == null) { continue; } foreach (KeyValuePair<string, FlagFieldBase> fieldCache in val.fieldCaches) { fieldCache.Deconstruct(out key, out var value2); string text2 = key; FlagFieldBase val3 = value2; JToken val4 = val2[text2]; if (val4 == null) { continue; } FlagFieldBool val5 = (FlagFieldBool)(object)((val3 is FlagFieldBool) ? val3 : null); if (val5 == null) { FlagFieldInt val6 = (FlagFieldInt)(object)((val3 is FlagFieldInt) ? val3 : null); if (val6 == null) { FlagFieldString val7 = (FlagFieldString)(object)((val3 is FlagFieldString) ? val3 : null); if (val7 == null) { FlagFieldFloat val8 = (FlagFieldFloat)(object)((val3 is FlagFieldFloat) ? val3 : null); if (val8 == null) { FlagFieldLong val9 = (FlagFieldLong)(object)((val3 is FlagFieldLong) ? val3 : null); if (val9 != null) { ((FlagField<long>)(object)val9).CurrentValue = Extensions.Value<long>((IEnumerable<JToken>)val4); } } else { ((FlagField<float>)(object)val8).CurrentValue = Extensions.Value<float>((IEnumerable<JToken>)val4); } } else { ((FlagField<string>)(object)val7).CurrentValue = Extensions.Value<string>((IEnumerable<JToken>)val4); } } else { ((FlagField<int>)(object)val6).CurrentValue = Extensions.Value<int>((IEnumerable<JToken>)val4); } } else { ((FlagField<bool>)(object)val5).CurrentValue = Extensions.Value<bool>((IEnumerable<JToken>)val4); } } } } } internal static class MonobehaviourTracing { private static readonly Type[] FindReferenceIgnoreList = new Type[17] { typeof(Transform), typeof(EffectDealer), typeof(GameLevel), typeof(PositionConstraint), typeof(PlayerInputCommandQueue), typeof(HackDrone), typeof(SpriteFlasher), typeof(PoolObject), typeof(PathArea), typeof(DamageScalarSource), typeof(PathToAreaFinder), typeof(MultiSpriteEffectController), typeof(IOnEnableInvokable), typeof(OnEnableHierarchyInvoker), typeof(EffectReceiver), typeof(SoundEmitter), typeof(SoundEmitter) }; private static readonly Type[] FindReferenceIgnoreListBase = new Type[5] { typeof(IAbstractEventReceiver), typeof(ILevelResetPrepare), typeof(ILevelResetStart), typeof(Renderer), typeof(Collider2D) }; public static void TraceReferencedMonobehaviours(Component origin, List<ComponentSnapshot> saved, HashSet<Component> seen, Component? onlyDescendantsOf, int depth = 0, int? maxDepth = null, int minDepth = 0) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown Scene scene = origin.gameObject.scene; if (!((Scene)(ref scene)).IsValid() || seen.Contains(origin)) { return; } if (depth >= minDepth) { saved.Add(ComponentSnapshot.Of(origin)); } seen.Add(origin); if (depth >= maxDepth) { return; } FieldInfo[] fields = ((object)origin).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo field in fields) { if (FindReferenceIgnoreList.Contains(field.FieldType) || Array.Exists(FindReferenceIgnoreListBase, (Type x) => x.IsAssignableFrom(field.FieldType))) { continue; } if (field.FieldType.IsArray) { Type elementType = field.FieldType.GetElementType(); if (!typeof(Component).IsAssignableFrom(elementType)) { continue; } Component[] array = (Component[])field.GetValue(origin); foreach (Component val in array) { if (Object.op_Implicit((Object)(object)val)) { if (!Object.op_Implicit((Object)(object)onlyDescendantsOf)) { TraceReferencedMonobehaviours(val, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth); } else if (val.transform.IsChildOf(onlyDescendantsOf.transform)) { TraceReferencedMonobehaviours(val, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth); } else if (!seen.Contains(val)) { Log.Info($"Skipping {val}: not child of {onlyDescendantsOf}"); } } } } if (!typeof(Component).IsAssignableFrom(field.FieldType)) { continue; } Component val2 = (Component)field.GetValue(origin); if (Object.op_Implicit((Object)(object)val2)) { if (!Object.op_Implicit((Object)(object)onlyDescendantsOf)) { TraceReferencedMonobehaviours(val2, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth); } else if (val2.transform.IsChildOf(onlyDescendantsOf.transform)) { TraceReferencedMonobehaviours(val2, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth); } else if (!seen.Contains(val2)) { Log.Info($"Skipping {val2}: not child of {onlyDescendantsOf}"); } } } } } [HarmonyPatch] public class Patches { [HarmonyPrefix] [HarmonyPatch(typeof(Actor), "OnRebindAnimatorMove")] [HarmonyPatch(typeof(Player), "OnRebindAnimatorMove")] [HarmonyPatch(typeof(MonsterBase), "OnRebindAnimatorMove")] public static bool PreventDuringLoad(MethodBase __originalMethod) { return !DebugModPlusInterop.IsLoadingSavestate; } } [Flags] public enum SavestateFilter { None = 0, Flags = 2, Player = 4, Monsters = 8, FSMs = 0x10, All = 0x1E } [Flags] public enum SavestateLoadMode { None = 0, ResetScene = 1, ReloadScene = 2 } public static class SavestateLogic { public static Savestate Create(SavestateFilter filter) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) if (!SingletonBehaviour<GameCore>.IsAvailable()) { throw new Exception("Can't create savestate outside of game level"); } GameCore instance = SingletonBehaviour<GameCore>.Instance; if (!Object.op_Implicit((Object)(object)instance.gameLevel)) { throw new Exception("Can't create savestate outside of game level"); } Player i = Player.i; List<ComponentSnapshot> list = new List<ComponentSnapshot>(); List<GameObjectSnapshot> list2 = new List<GameObjectSnapshot>(); List<MonsterLoveFsmSnapshot> list3 = new List<MonsterLoveFsmSnapshot>(); List<GeneralFsmSnapshot> list4 = new List<GeneralFsmSnapshot>(); List<ReferenceFixups> list5 = new List<ReferenceFixups>(); JObject val = new JObject(); HashSet<Component> seen = new HashSet<Component>(); if (filter.HasFlag(SavestateFilter.Player)) { list.Add(ComponentSnapshot.Of((Component)(object)((Component)i).transform)); list2.Add(GameObjectSnapshot.Of(((Component)i.pushAwayCollider).gameObject)); SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)i, list, seen); foreach (var state in ((IStateMachine)(object)i.fsm).GetStates()) { SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)state.Item2, list, seen, 0); } SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)SingletonBehaviour<CameraManager>.Instance.camera2D, list, seen, 0); } if (filter.HasFlag(SavestateFilter.Monsters)) { MonsterBase[] array = Object.FindObjectsOfType<MonsterBase>(); foreach (MonsterBase val2 in array) { list.Add(ComponentSnapshot.Of((Component)(object)((Component)val2).transform)); SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)val2, list, seen); list3.Add(MonsterLoveFsmSnapshot.Of((IStateMachine)(object)val2.fsm)); AttackSensor[] attackSensors = val2.attackSensors; for (int k = 0; k < attackSensors.Length; k++) { SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)attackSensors[k], list, seen); } foreach (var state2 in ((IStateMachine)(object)val2.fsm).GetStates()) { SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)state2.Item2, list, seen); } } } if (filter.HasFlag(SavestateFilter.FSMs)) { StateMachineOwner[] array2 = Object.FindObjectsOfType<StateMachineOwner>(); foreach (StateMachineOwner owner in array2) { list4.Add(GeneralFsmSnapshot.Of(owner)); } } if (filter.HasFlag(SavestateFilter.Player)) { list3.Add(MonsterLoveFsmSnapshot.Of((IStateMachine)(object)i.fsm)); list5.Add(ReferenceFixups.Of((MonoBehaviour)(object)Player.i, new List<ReferenceFixupField>(1) { new ReferenceFixupField("touchingRope", ObjectUtils.ObjectComponentPath((Component)(object)Player.i.touchingRope)) })); } if (filter.HasFlag(SavestateFilter.Flags)) { val = JObject.Parse(GameFlagManager.FlagsToJson(SingletonBehaviour<SaveManager>.Instance.allFlags)); } Savestate obj = new Savestate { Flags = ((((JContainer)val).Count == 0) ? null : val) }; Scene scene = ((Component)instance.gameLevel).gameObject.scene; obj.Scene = ((Scene)(ref scene)).name; obj.PlayerPosition = ((Component)i).transform.position; obj.LastTeleportId = ((GameFlagBase)SingletonBehaviour<ApplicationCore>.Instance.lastSaveTeleportPoint).FinalSaveID; obj.MonobehaviourSnapshots = list; obj.GameObjectSnapshots = list2; obj.FsmSnapshots = ((list3.Count == 0) ? null : list3); obj.GeneralFsmSnapshots = ((list4.Count == 0) ? null : list4); obj.ReferenceFixups = ((list5.Count == 0) ? null : list5); obj.RandomState = Random.state; return obj; } public static async Task Load(Savestate savestate, SavestateLoadMode loadMode) { try { DebugModPlusInterop.IsLoadingSavestate = true; await LoadInner(savestate, loadMode); } finally { DebugModPlusInterop.IsLoadingSavestate = false; } } private static async Task LoadInner(Savestate savestate, SavestateLoadMode loadMode) { if (!SingletonBehaviour<GameCore>.IsAvailable()) { throw new Exception("Attempted to load savestate outside of scene"); } if (savestate.LastTeleportId != null) { TeleportPointData teleportPointWithPath = SingletonBehaviour<GameFlagManager>.Instance.GetTeleportPointWithPath(savestate.LastTeleportId); SingletonBehaviour<ApplicationCore>.Instance.lastSaveTeleportPoint = teleportPointWithPath; } Stopwatch sw = Stopwatch.StartNew(); sw.Start(); JObject flags = savestate.Flags; if (flags != null) { FlagLogic.LoadFlags(flags, SingletonBehaviour<SaveManager>.Instance.allFlags); Log.Debug($"- Applied flags in {sw.ElapsedMilliseconds}ms"); SingletonBehaviour<SaveManager>.Instance.allFlags.AllFlagInitStartAndEquip(); } if (SingletonBehaviour<DialoguePlayer>.Instance.CanSkip) { SingletonBehaviour<DialoguePlayer>.Instance.ForceClose(); } string? scene = savestate.Scene; GameLevel gameLevel = SingletonBehaviour<GameCore>.Instance.gameLevel; bool flag = scene == ((gameLevel != null) ? gameLevel.SceneName : null); if (savestate.Scene != null) { if ((savestate.Scene != null && !flag) || loadMode.HasFlag(SavestateLoadMode.ReloadScene)) { Vector3 playerPosition = savestate.PlayerPosition ?? throw new Exception("Savestate with scene must have `playerPosition`"); sw.Restart(); Task task = ChangeSceneAsync(new ChangeSceneData { sceneName = savestate.Scene, playerSpawnPosition = (SpawnPositionDelegate)(() => playerPosition) }); if (await Task.WhenAny(new Task[2] { task, Task.Delay(5000) }) != task) { ToastManager.Toast((object)"Savestate was not loaded after 5s, aborting"); return; } Log.Info($"- Change scene in {sw.ElapsedMilliseconds}ms"); } } else { Vector3? playerPosition2 = savestate.PlayerPosition; if (playerPosition2.HasValue) { Vector3 valueOrDefault = playerPosition2.GetValueOrDefault(); ((Component)Player.i).transform.position = valueOrDefault; } } if (loadMode.HasFlag(SavestateLoadMode.ResetScene)) { SingletonBehaviour<GameCore>.Instance.ResetLevel(false); } sw.Restart(); if (savestate.MonobehaviourSnapshots != null) { foreach (ComponentSnapshot monobehaviourSnapshot in savestate.MonobehaviourSnapshots) { monobehaviourSnapshot.Restore(); } Log.Info($"- Applied snapshots to scene in {sw.ElapsedMilliseconds}ms"); } sw.Stop(); foreach (GameObjectSnapshot item in savestate.GameObjectSnapshots ?? new List<GameObjectSnapshot>()) { item.Restore(); } if (savestate.ReferenceFixups != null) { ApplyFixups(savestate.ReferenceFixups); } foreach (MonsterLoveFsmSnapshot item2 in savestate.FsmSnapshots ?? new List<MonsterLoveFsmSnapshot>()) { GameObject val = ObjectUtils.LookupPath(item2.Path); if ((Object)(object)val == (Object)null) { Log.Error("Savestate stored monsterlove fsm state on " + item2.Path + ", which does not exist at load time"); continue; } FSMStateMachineRunner component = val.GetComponent<FSMStateMachineRunner>(); if (!Object.op_Implicit((Object)(object)component)) { Log.Error("Savestate stored monsterlove fsm state on " + item2.Path + ", which has no FSMStateMachineRunner"); continue; } foreach (IStateMachine machine in component.GetMachines()) { object stateObj = Enum.ToObject(machine.CurrentStateMap.stateObj.GetType(), item2.CurrentState); EnterStateDirectly(machine, stateObj); } } foreach (GeneralFsmSnapshot fsm in savestate.GeneralFsmSnapshots ?? new List<GeneralFsmSnapshot>()) { GameObject val2 = ObjectUtils.LookupPath(fsm.Path); if ((Object)(object)val2 == (Object)null) { Log.Error("Savestate stored general fsm state on " + fsm.Path + ", which does not exist at load time"); continue; } StateMachineOwner component2 = val2.GetComponent<StateMachineOwner>(); if (!Object.op_Implicit((Object)(object)component2)) { Log.Error("Savestate stored general fsm state on " + fsm.Path + ", which has no FSMStateMachineRunner"); continue; } GeneralState val3 = ((IEnumerable<GeneralState>)((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).States).FirstOrDefault((Func<GeneralState, bool>)((GeneralState state) => ((Object)state).name == fsm.CurrentState)); if (!Object.op_Implicit((Object)(object)val3)) { Log.Error("State " + fsm.CurrentState + " does not exist on " + fsm.Path); continue; } try { ((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).ChangeState(val3); } catch (Exception arg) { Log.Error($"Could not apply fsm state on {component2.FsmContext}/{((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).fsm} {arg}"); } } Player.i.playerInput.RevokeAllMyVote((MonoBehaviour)(object)Player.i.PlayerDeadState); Tween.StopAll((object)null); BossArea[] array = Object.FindObjectsOfType<BossArea>(); for (int i = 0; i < array.Length; i++) { array[i].ForceShowHP(); } foreach (RuntimeConditionVote item3 in ReflectionExtension.GetFieldValue<List<RuntimeConditionVote>>((object)Player.i.playerInput, "conditionVoteList")) { item3.votes.Clear(); item3.ManualUpdate(); } State? randomState = savestate.RandomState; if (randomState.HasValue) { State valueOrDefault2 = randomState.GetValueOrDefault(); Random.state = valueOrDefault2; } Player.i.UpdateSpriteFacing(); } private static void ApplyFixups(List<ReferenceFixups> fixups) { foreach (ReferenceFixups fixup in fixups) { Component val = ObjectUtils.LookupObjectComponentPath(fixup.Path); if ((Object)(object)val == (Object)null) { Log.Error("Savestate stored reference fixup on " + fixup.Path + ", which does not exist at load time"); continue; } foreach (ReferenceFixupField field2 in fixup.Fields) { field2.Deconstruct(out string Field, out string Reference); string text = Field; string text2 = Reference; FieldInfo field = ((object)val).GetType().GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (text2 == null) { field.SetValue(val, null); continue; } Component val2 = ObjectUtils.LookupObjectComponentPath(text2); if ((Object)(object)val2 == (Object)null) { Log.Error("Savestate stored reference fixup on " + fixup.Path + "." + text + ", but the target " + text2 + " does not exist at load time"); } else { field.SetValue(val, val2); } } } } private static void EnterStateDirectly(IStateMachine sm, object stateObj) { FSMStateMachineRunner fieldValue = ReflectionExtension.GetFieldValue<FSMStateMachineRunner>((object)sm, "engine"); IDictionary fieldValue2 = ReflectionExtension.GetFieldValue<IDictionary>((object)sm, "stateLookup"); if (!fieldValue2.Contains(stateObj)) { throw new Exception($"state {stateObj} not found in fsm"); } object value = fieldValue2[stateObj]; Type type = ((object)sm).GetType(); FieldInfo fieldInfo = ReflectionExtension.GetFieldInfo(type, "queuedChange", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true); FieldInfo fieldInfo2 = ReflectionExtension.GetFieldInfo(type, "currentTransition", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true); FieldInfo fieldInfo3 = ReflectionExtension.GetFieldInfo(type, "exitRoutine", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true); FieldInfo fieldInfo4 = ReflectionExtension.GetFie