using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [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("UndoEverywhere")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+2cd7dffe237c43664f261c2e9e93d030f595de9b")] [assembly: AssemblyProduct("UndoEverywhere")] [assembly: AssemblyTitle("UndoEverywhere")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace UndoEverywhere { [BepInPlugin("UndoEverywhere", "UndoEverywhere", "0.1.0")] public class Plugin : BaseUnityPlugin { private class CoroutineRunner : MonoBehaviour { } internal static ManualLogSource Logger = new ManualLogSource("UndoEverywhere"); private static CoroutineRunner? coroutineRunner; public void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Plugin UndoEverywhere is loaded!"); new Harmony("UndoEverywhere").PatchAll(); } internal static Coroutine RunCoroutine(IEnumerator routine) { //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) //IL_001d: Expected O, but got Unknown if ((Object)(object)coroutineRunner == (Object)null) { GameObject val = new GameObject("CoroutineRunner"); Object.DontDestroyOnLoad((Object)val); coroutineRunner = val.AddComponent(); } return ((MonoBehaviour)coroutineRunner).StartCoroutine(routine); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "UndoEverywhere"; public const string PLUGIN_NAME = "UndoEverywhere"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace UndoEverywhere.Patches { [HarmonyPatch(typeof(PauseDialog), "ShouldShowRestartBattleButton")] internal static class PauseDialog_RestartOutsideBattle_Patch { private static void Postfix(SaveManager ___saveManager, ref bool __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!__result && !((Object)(object)___saveManager == (Object)null) && StageStartMarker.HasCheckpoint(___saveManager) && StageStartMarker.IsRestartableState(___saveManager.GetGameSequence())) { __result = true; } } } [HarmonyPatch(typeof(PauseDialog), "RefreshRestartBattleButton")] internal static class PauseDialog_RestartLabel_Patch { private static string? vanillaText; private static void Postfix(SaveManager ___saveManager, TMP_Text ___restartBattleNormalLabel) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (vanillaText == null) { vanillaText = ___restartBattleNormalLabel.text; } bool flag = (Object)(object)___saveManager != (Object)null && !___saveManager.IsInBattle() && StageStartMarker.HasCheckpoint(___saveManager) && StageStartMarker.IsRestartableState(___saveManager.GetGameSequence()); ___restartBattleNormalLabel.text = (flag ? "Restart Ring" : vanillaText); } } [HarmonyPatch(typeof(SaveManager), "RestartBattle")] internal static class SaveManager_RestartStage_Patch { private static bool Prefix(SaveManager __instance) { if (__instance.IsInBattle()) { return true; } if (!StageStartMarker.TryGetCheckpointJson(__instance, out string json)) { Plugin.Logger.LogWarning((object)"[SaveManager_RestartStage_Patch] no stage-start checkpoint set, aborting restart"); return false; } try { Plugin.RunCoroutine(RestartStageCoroutine(__instance, json)); } catch (Exception arg) { Plugin.Logger.LogError((object)$"[SaveManager_RestartStage_Patch] exception starting coroutine: {arg}"); } return false; } private static IEnumerator RestartStageCoroutine(SaveManager saveManager, string checkpointJson) { try { JsonUtility.FromJsonOverwrite(checkpointJson, StageStartMarker.GetActiveSaveData(saveManager)); } catch (Exception arg) { Plugin.Logger.LogError((object)$"[SaveManager_RestartStage_Patch] exception restoring checkpoint: {arg}"); yield break; } GameStateManager gameStateManager = AllGameManagers.Instance.GetGameStateManager(); ScreenManager screenManager = AllGameManagers.Instance.GetScreenManager(); RunType runType = saveManager.GetRunType(); string sharecode = saveManager.GetShareCode(); gameStateManager.LeaveGame(); screenManager.ReturnToMainMenu(); yield return (object)new WaitUntil((Func)(() => screenManager.GetScreenActive((ScreenName)15))); yield return null; yield return null; yield return null; bool runLoaded = false; gameStateManager.ContinueRun(runType, sharecode, (Action)delegate { runLoaded = true; }); yield return (object)new WaitUntil((Func)(() => runLoaded)); } } internal static class StageStartMarker { private static readonly PropertyInfo ActiveSaveDataProperty = AccessTools.Property(typeof(SaveManager), "ActiveSaveData"); private static string CheckpointPath(SaveManager saveManager) { return saveManager.ActiveSavePath + ".stagestart"; } internal static object GetActiveSaveData(SaveManager saveManager) { return ActiveSaveDataProperty.GetValue(saveManager); } internal static void CaptureCurrent(SaveManager saveManager) { try { string contents = JsonUtility.ToJson(GetActiveSaveData(saveManager)); File.WriteAllText(CheckpointPath(saveManager), contents); } catch (Exception arg) { Plugin.Logger.LogError((object)$"[StageStartMarker] failed to capture checkpoint: {arg}"); } } internal static bool HasCheckpoint(SaveManager saveManager) { return File.Exists(CheckpointPath(saveManager)); } internal static bool TryGetCheckpointJson(SaveManager saveManager, out string json) { string path = CheckpointPath(saveManager); if (!File.Exists(path)) { json = string.Empty; return false; } json = File.ReadAllText(path); return true; } internal static bool IsRestartableState(GameSequence sequence) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)sequence != 1 && (int)sequence != 6 && (int)sequence != 4) { return (int)sequence > 0; } return false; } } [HarmonyPatch(typeof(GameStateManager), "StartNewRun")] internal static class GameStateManager_StageStartMarker_Patch { private static void Postfix() { AllGameManagers instance = AllGameManagers.Instance; SaveManager val = ((instance != null) ? instance.GetSaveManager() : null); if ((Object)(object)val != (Object)null) { StageStartMarker.CaptureCurrent(val); } } } [HarmonyPatch(typeof(GameScreen), "ShowScreenAfterBattle")] internal static class GameScreen_StageStartMarker_Patch { private static void Postfix(SaveManager ___saveManager) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)___saveManager.GetGameSequence() != 4) { StageStartMarker.CaptureCurrent(___saveManager); } } } }