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 I2.Loc;
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.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+da9132471a7af5c5bfea701892d3a40e890544c5")]
[assembly: AssemblyProduct("UndoEverywhere")]
[assembly: AssemblyTitle("UndoEverywhere")]
[assembly: AssemblyVersion("0.3.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("SpecialCircumstances.UndoEverywhere", "UndoEverywhere", "0.3.0")]
public class Plugin : BaseUnityPlugin
{
private class CoroutineRunner : MonoBehaviour
{
}
internal static ManualLogSource Logger = new ManualLogSource("SpecialCircumstances.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 SpecialCircumstances.UndoEverywhere is loaded!");
Harmony val = new Harmony("SpecialCircumstances.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 = "SpecialCircumstances.UndoEverywhere";
public const string PLUGIN_NAME = "UndoEverywhere";
public const string PLUGIN_VERSION = "0.3.0";
}
}
namespace UndoEverywhere.Patches
{
[HarmonyPatch(typeof(PauseDialog), "ShouldShowRestartBattleButton")]
internal static class PauseDialog_RestartOutsideBattle_Patch
{
private static void Postfix(SaveManager ___saveManager, ref bool __result)
{
if (!__result && (Object)(object)___saveManager != (Object)null)
{
__result = StageStartMarker.CanRestartStage(___saveManager);
}
}
}
[HarmonyPatch(typeof(PauseDialog), "RefreshRestartBattleButton")]
internal static class PauseDialog_RestartLabel_Patch
{
internal static bool RingRestartArmed { get; private set; }
internal static string? VanillaConfirmKey { get; private set; }
private static void Postfix(SaveManager ___saveManager, TMP_Text ___restartBattleNormalLabel, string ___confirmRestartBattleKey)
{
int num;
if ((Object)(object)___saveManager != (Object)null && !___saveManager.IsInBattle())
{
num = (StageStartMarker.CanRestartStage(___saveManager) ? 1 : 0);
if (num != 0)
{
___restartBattleNormalLabel.text = "Restart Ring";
goto IL_0043;
}
}
else
{
num = 0;
}
if (RingRestartArmed)
{
Localize component = ((Component)___restartBattleNormalLabel).GetComponent<Localize>();
if (component != null)
{
component.OnLocalize(true);
}
}
goto IL_0043;
IL_0043:
RingRestartArmed = (byte)num != 0;
VanillaConfirmKey = ___confirmRestartBattleKey;
}
}
[HarmonyPatch(typeof(ScreenManager), "ShowConfirmationDialog")]
internal static class ScreenManager_RingRestartConfirmText_Patch
{
private static void Prefix(ref string content)
{
if (PauseDialog_RestartLabel_Patch.RingRestartArmed)
{
string vanillaConfirmKey = PauseDialog_RestartLabel_Patch.VanillaConfirmKey;
if (!string.IsNullOrEmpty(vanillaConfirmKey) && content == LocalizationExtensions.Localize(vanillaConfirmKey, (ILocalizationParameterContext)null))
{
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, (object)StageStartMarker.GetActiveSaveData(saveManager));
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[SaveManager_RestartStage_Patch] exception restoring checkpoint: {arg}");
yield break;
}
AllGameManagers instance = AllGameManagers.Instance;
GameStateManager gameStateManager = instance.GetGameStateManager();
ScreenManager screenManager = 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 SaveData? GetActiveSaveData(SaveManager saveManager)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
return (SaveData)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
{
File.WriteAllText(text, JsonUtility.ToJson((object)GetActiveSaveData(saveManager)));
InvalidateRunIdCache();
}
catch (Exception arg)
{
Plugin.Logger.LogError((object)$"[StageStartMarker] failed to capture checkpoint ({reason}) to '{text}': {arg}");
}
}
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 void InvalidateRunIdCache()
{
cachedPath = null;
cachedRunId = null;
}
private static string? CurrentRunCheckpoint(SaveManager saveManager)
{
string text = CheckpointPath(saveManager);
SaveData? activeSaveData = GetActiveSaveData(saveManager);
string text2 = ((activeSaveData != null) ? ((BaseSaveData)activeSaveData).GetID() : null);
if (text == null || string.IsNullOrEmpty(text2) || !(CheckpointRunId(text) == text2))
{
return null;
}
return text;
}
internal static bool HasCheckpoint(SaveManager saveManager)
{
return CurrentRunCheckpoint(saveManager) != null;
}
internal static bool TryGetCheckpointJson(SaveManager saveManager, out string json)
{
string text = CurrentRunCheckpoint(saveManager);
json = ((text == null) ? string.Empty : File.ReadAllText(text));
return text != 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 CanRestartStage(SaveManager saveManager)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
if (HasCheckpoint(saveManager))
{
return IsRestartableState(saveManager.GetGameSequence());
}
return false;
}
private 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");
}
}
}
}