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.2.3.0")]
[assembly: AssemblyInformationalVersion("0.2.3+551a0b5ba64814d29c82a426a5a310a0632ffcd3")]
[assembly: AssemblyProduct("UndoEverywhere")]
[assembly: AssemblyTitle("UndoEverywhere")]
[assembly: AssemblyVersion("0.2.3.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.2.3")]
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)
//IL_0025: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"Plugin UndoEverywhere is loaded!");
Harmony val = new Harmony("UndoEverywhere");
try
{
val.PatchAll();
}
catch (Exception arg)
{
Logger.LogError((object)$"PatchAll failed -- some patches are NOT applied: {arg}");
}
}
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<CoroutineRunner>();
}
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.2.3";
}
}
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;
internal static bool RingRestartArmed { get; private set; }
internal static string? VanillaConfirmText { get; private set; }
private static void Postfix(SaveManager ___saveManager, TMP_Text ___restartBattleNormalLabel, string ___confirmRestartBattleKey)
{
//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);
RingRestartArmed = flag;
if (flag)
{
VanillaConfirmText = (string.IsNullOrEmpty(___confirmRestartBattleKey) ? null : LocalizationExtensions.Localize(___confirmRestartBattleKey, (ILocalizationParameterContext)null));
}
}
}
[HarmonyPatch(typeof(ScreenManager), "ShowConfirmationDialog")]
internal static class ScreenManager_RingRestartConfirmText_Patch
{
private static void Prefix(ref string content)
{
if (PauseDialog_RestartLabel_Patch.RingRestartArmed)
{
string vanillaConfirmText = PauseDialog_RestartLabel_Patch.VanillaConfirmText;
if (!string.IsNullOrEmpty(vanillaConfirmText) && content == vanillaConfirmText)
{
content = "Are you sure you want to restart the current ring?";
}
}
}
}
[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<bool>)(() => screenManager.GetScreenActive((ScreenName)15)));
yield return null;
yield return null;
yield return null;
bool runLoaded = false;
gameStateManager.StartGame(runType, sharecode, (Action)delegate
{
runLoaded = true;
});
yield return (object)new WaitUntil((Func<bool>)(() => runLoaded));
}
}
internal static class StageStartMarker
{
[Serializable]
private class CheckpointHeader
{
public string id = string.Empty;
}
private static readonly PropertyInfo ActiveSaveDataProperty = AccessTools.Property(typeof(SaveManager), "ActiveSaveData");
private static string? cachedPath;
private static DateTime cachedStamp;
private static long cachedLength;
private static string? cachedRunId;
private static string? CheckpointPath(SaveManager saveManager)
{
string activeSavePath = saveManager.ActiveSavePath;
if (!string.IsNullOrEmpty(activeSavePath))
{
return activeSavePath + ".stagestart";
}
return null;
}
internal static object GetActiveSaveData(SaveManager saveManager)
{
return ActiveSaveDataProperty.GetValue(saveManager);
}
private static bool HasRealRun(SaveManager saveManager)
{
if (saveManager.HasRun((RunType)(-1), "", true))
{
return saveManager.GetCurrentDistance() >= 0;
}
return false;
}
internal static void CaptureCurrent(SaveManager saveManager, string reason)
{
string text = CheckpointPath(saveManager);
if (text == null || !HasRealRun(saveManager))
{
Plugin.Logger.LogDebug((object)("[StageStartMarker] skipped capture (" + reason + "): no set-up run yet"));
return;
}
try
{
string contents = JsonUtility.ToJson(GetActiveSaveData(saveManager));
File.WriteAllText(text, contents);
InvalidateRunIdCache();
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[StageStartMarker] failed to capture checkpoint ({reason}) to '{text}': {arg}");
}
}
private static string? LiveRunId(SaveManager saveManager)
{
object activeSaveData = GetActiveSaveData(saveManager);
object obj = ((activeSaveData is SaveData) ? activeSaveData : null);
if (obj == null)
{
return null;
}
return ((BaseSaveData)obj).GetID();
}
private static string? CheckpointRunId(string path)
{
FileInfo fileInfo = new FileInfo(path);
if (!fileInfo.Exists)
{
return null;
}
if (path == cachedPath && fileInfo.LastWriteTimeUtc == cachedStamp && fileInfo.Length == cachedLength)
{
return cachedRunId;
}
try
{
cachedRunId = JsonUtility.FromJson<CheckpointHeader>(File.ReadAllText(path))?.id;
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[StageStartMarker] failed to read checkpoint run id from '{path}': {arg}");
cachedRunId = null;
}
cachedPath = path;
cachedStamp = fileInfo.LastWriteTimeUtc;
cachedLength = fileInfo.Length;
return cachedRunId;
}
private static bool IsCheckpointForCurrentRun(SaveManager saveManager, string path)
{
string text = LiveRunId(saveManager);
if (!string.IsNullOrEmpty(text))
{
return CheckpointRunId(path) == text;
}
return false;
}
internal static bool HasCheckpoint(SaveManager saveManager)
{
string text = CheckpointPath(saveManager);
if (text != null)
{
return IsCheckpointForCurrentRun(saveManager, text);
}
return false;
}
private static void InvalidateRunIdCache()
{
cachedPath = null;
cachedRunId = null;
}
internal static void DeleteCheckpoint(SaveManager saveManager, string reason)
{
string text = CheckpointPath(saveManager);
if (text == null || !File.Exists(text))
{
return;
}
try
{
File.Delete(text);
InvalidateRunIdCache();
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[StageStartMarker] failed to delete checkpoint ({reason}) at '{text}': {arg}");
}
}
internal static bool TryGetCheckpointJson(SaveManager saveManager, out string json)
{
string text = CheckpointPath(saveManager);
if (text == null || !IsCheckpointForCurrentRun(saveManager, text))
{
json = string.Empty;
return false;
}
json = File.ReadAllText(text);
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(MapScreen), "HandleCurrentGameSequence")]
internal static class MapScreen_StageStartBackfill_Patch
{
private static void Postfix(SaveManager ___saveManager)
{
if ((Object)(object)___saveManager != (Object)null && ___saveManager.IsAlive() && !StageStartMarker.HasCheckpoint(___saveManager))
{
StageStartMarker.CaptureCurrent(___saveManager, "MapScreen.HandleCurrentGameSequence");
}
}
}
[HarmonyPatch(typeof(GameStateManager), "EndGame")]
internal static class GameStateManager_ClearCheckpointOnRunEnd_Patch
{
private static void Postfix(EndGameReason endGameReason)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Invalid comparison between Unknown and I4
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
AllGameManagers instance = AllGameManagers.Instance;
SaveManager val = ((instance != null) ? instance.GetSaveManager() : null);
if ((Object)(object)val != (Object)null && (int)val.GetGameSequence() == 4)
{
StageStartMarker.DeleteCheckpoint(val, $"run ended ({endGameReason})");
}
}
}
[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, "ShowScreenAfterBattle");
}
}
}
}