Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DeathNoSaveDelete v1.0.1
DeathNoSaveDelete.dll
Decompiled 6 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DeathNoSaveDelete")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+272c8cd2fe7287a90d058372cd13fd27b710942e")] [assembly: AssemblyProduct("DeathNoSaveDelete")] [assembly: AssemblyTitle("DeathNoSaveDelete")] [assembly: AssemblyVersion("1.0.0.0")] namespace DeathNoSaveDelete; [BepInPlugin("com.hermit.deathnosavedelete", "死亡不删档", "1.1.0")] public sealed class DeathNoSaveDeletePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(RunManager), "ChangeLevel")] private static class RunManagerChangeLevelPatch { private static bool Prefix(bool _levelFailed, RunManager __instance) { if (!_levelFailed) { return true; } if (!ShouldProtectFailure(__instance)) { return true; } if (EnableSameLevelRetry.Value) { return !TryStartSameLevelRetry(__instance); } BeginProtection("ChangeLevel(levelFailed=true)"); return true; } } [HarmonyPatch(typeof(RunManager), "ResetProgress")] private static class RunManagerResetProgressPatch { private static bool Prefix() { if (!EnableProtection.Value || !BlockArenaPersistence.Value || !IsRunArenaSafe()) { return true; } BeginProtection("ResetProgress in arena"); return AllowOriginalOrLog("RunManager.ResetProgress"); } } [HarmonyPatch(typeof(RoundDirector), "StartRoundLogic")] private static class RoundDirectorStartRoundLogicPatch { private static void Prefix(RoundDirector __instance) { if (!EnableSameLevelRetry.Value || (Object)(object)__instance == (Object)null) { return; } if (_retryInProgress) { if (VerboseLogging.Value) { Log.LogInfo((object)"同关重试进行中,跳过本次状态记录。"); } } else { ((MonoBehaviour)__instance).StartCoroutine(SaveRetryStateDelayed()); } } private static void Postfix(RoundDirector __instance) { if (EnableSameLevelRetry.Value && _retryInProgress && !((Object)(object)__instance == (Object)null)) { ((MonoBehaviour)__instance).StartCoroutine(HandleRetryRestore()); } } } [HarmonyPatch(typeof(MenuPageServerListCreateNew), "ButtonConfirm")] private static class MenuPageServerListCreateNewButtonConfirmPatch { private static bool Prefix(MenuPageServerListCreateNew __instance) { return !TryHandlePublicGameHost(__instance); } } [HarmonyPatch(typeof(SemiFunc), "MenuActionHostGame")] private static class SemiFuncMenuActionHostGamePatch { private static bool Prefix(ref string saveFileName, ref List<string> saveFileBackups) { return !TryContinuePublicGame(ref saveFileName, ref saveFileBackups); } } [HarmonyPatch(typeof(SemiFunc), "SaveFileSave")] private static class SemiFuncSaveFileSavePatch { private static bool Prefix() { if (ShouldBlockDangerousPersistence()) { if (VerboseLogging.Value) { Log.LogInfo((object)"已拦截 SemiFunc.SaveFileSave"); } return false; } if (!EnablePublicSaves.Value || !IsPublicLobbySafe()) { return true; } if ((Object)(object)StatsManager.instance != (Object)null) { StatsManager.instance.SaveFileSave(); } return false; } } [HarmonyPatch(typeof(SemiFunc), "SaveFileDelete")] private static class SemiFuncSaveFileDeletePatch { private static bool Prefix(string saveFileName) { if (ShouldBlockDangerousPersistence()) { if (VerboseLogging.Value) { Log.LogInfo((object)("已拦截 SemiFunc.SaveFileDelete(" + saveFileName + ")")); } return false; } if (EnablePublicSaves.Value && IsPublicLobbySafe()) { if (VerboseLogging.Value) { Log.LogInfo((object)("公开房已阻止删档: " + saveFileName)); } return false; } return true; } } [HarmonyPatch(typeof(DataDirector), "SaveDeleteCheck")] private static class DataDirectorSaveDeleteCheckPatch { private static bool Prefix() { return AllowOriginalOrLog("DataDirector.SaveDeleteCheck"); } } [HarmonyPatch(typeof(StatsManager), "SaveFileDelete")] private static class StatsManagerSaveFileDeletePatch { private static bool Prefix(string saveFileName) { return AllowOriginalOrLog("StatsManager.SaveFileDelete(" + saveFileName + ")"); } } [HarmonyPatch(typeof(StatsManager), "SaveGame")] private static class StatsManagerSaveGamePatch { private static bool Prefix(string fileName) { return AllowOriginalOrLog("StatsManager.SaveGame(" + fileName + ")"); } } [HarmonyPatch(typeof(StatsManager), "SaveFileSave")] private static class StatsManagerSaveFileSavePatch { private static bool Prefix() { return AllowOriginalOrLog("StatsManager.SaveFileSave"); } } [CompilerGenerated] private sealed class <HandleRetryRestore>d__63 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <HandleRetryRestore>d__63(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; try { RestoreRetryState(); Log.LogInfo((object)"同关重试状态已恢复。"); } catch (Exception ex) { Log.LogWarning((object)("恢复同关重试状态失败: " + ex.Message)); } finally { _retryInProgress = false; ClearProtectionState(startCooldown: true); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <SaveRetryStateDelayed>d__62 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SaveRetryStateDelayed>d__62(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1.5f); <>1__state = 1; return true; case 1: <>1__state = -1; if (!EnableSameLevelRetry.Value || _retryInProgress) { return false; } try { List<PlayerAvatar> list = SemiFunc.PlayerGetAll(); if (list == null || list.Count == 0) { return false; } PlayerHealth playerHealth = list[0].playerHealth; _savedHealth = ReadIntField(AccessTools.Field(typeof(PlayerHealth), "health"), playerHealth, _savedHealth); _savedMoney = GetRunMoney(); SaveChargingStationState(); SaveItemBatteryCharges(); _hasRetrySnapshot = true; if (VerboseLogging.Value) { Log.LogInfo((object)$"已记录重试状态: 血量={_savedHealth}, 金钱={_savedMoney}, 充电站电量={_savedChargeTotal}, 道具电池={SavedItemCharges.Count}"); } } catch (Exception ex) { Log.LogWarning((object)("记录同关重试状态失败: " + ex.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string PluginGuid = "com.hermit.deathnosavedelete"; private const float ProtectionRearmCooldownSeconds = 2f; private static ManualLogSource Log; private static ConfigEntry<bool> EnableProtection; private static ConfigEntry<bool> ReloadAfterFailure; private static ConfigEntry<bool> BlockArenaPersistence; private static ConfigEntry<bool> VerboseLogging; private static ConfigEntry<float> ReloadDelaySeconds; private static ConfigEntry<bool> EnablePublicSaves; private static ConfigEntry<bool> EnablePublicGameContinueSave; private static ConfigEntry<bool> ShowPingHud; private static ConfigEntry<bool> EnableSameLevelRetry; private static ConfigEntry<bool> RestoreRetryHealth; private static ConfigEntry<bool> RestoreRetryMoney; private static ConfigEntry<bool> RestoreRetryEnergy; private static ConfigEntry<bool> RestoreRetryItemBatteries; private static readonly FieldInfo StatsSaveFileCurrentField = AccessTools.Field(typeof(StatsManager), "saveFileCurrent"); private static readonly MethodInfo StatsLoadGameMethod = AccessTools.Method(typeof(StatsManager), "LoadGame", new Type[2] { typeof(string), typeof(List<string>) }, (Type[])null); private static readonly FieldInfo LevelGeneratorInstanceField = AccessTools.Field(typeof(LevelGenerator), "Instance"); private static readonly FieldInfo LevelGeneratorGeneratedField = AccessTools.Field(typeof(LevelGenerator), "Generated"); private static readonly FieldInfo RunLevelCurrentField = AccessTools.Field(typeof(RunManager), "levelCurrent"); private static readonly FieldInfo RunLevelLobbyField = AccessTools.Field(typeof(RunManager), "levelLobby"); private static readonly FieldInfo RunLevelLobbyMenuField = AccessTools.Field(typeof(RunManager), "levelLobbyMenu"); private static readonly FieldInfo RunLevelMainMenuField = AccessTools.Field(typeof(RunManager), "levelMainMenu"); private static readonly FieldInfo RunLevelTutorialField = AccessTools.Field(typeof(RunManager), "levelTutorial"); private static readonly FieldInfo RunLevelRecordingField = AccessTools.Field(typeof(RunManager), "levelRecording"); private static readonly FieldInfo RunLevelArenaField = AccessTools.Field(typeof(RunManager), "levelArena"); private static readonly FieldInfo RunWaitToChangeSceneField = AccessTools.Field(typeof(RunManager), "waitToChangeScene"); private static readonly FieldInfo RunLobbyJoinField = AccessTools.Field(typeof(RunManager), "lobbyJoin"); private static readonly FieldInfo DataNetworkServerNameField = AccessTools.Field(typeof(DataDirector), "networkServerName"); private static readonly FieldInfo MenuTextInputTextCurrentField = AccessTools.Field(typeof(MenuTextInput), "textCurrent"); private static bool _blockSaves; private static bool _needsReload; private static float _reloadTimer; private static float _ignoreProtectionUntil; private static string _activeProtectionReason; private static bool _hostedPublicGame; private static bool _retryInProgress; private static int _savedChargeTotal = -1; private static int _savedHealth = -1; private static int _savedMoney; private static bool _hasRetrySnapshot; private static readonly Dictionary<string, float> SavedItemCharges = new Dictionary<string, float>(); private static GameObject _pingHudObject; private static TextMeshProUGUI _pingText; private static DeathNoSaveDeletePlugin _instance; private Harmony _harmony; private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _instance = this; BindConfig(); _harmony = new Harmony("com.hermit.deathnosavedelete"); _harmony.PatchAll(); Log.LogInfo((object)"死亡不删档 1.1.0 已加载。已融合公开房存档、公开房继续存档、同关重试和 Ping 显示功能。"); } private void BindConfig() { EnableProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("0.总开关", "启用死亡不删档", true, "开启后死亡、团灭、失败时阻止删档和破坏性保存"); ReloadAfterFailure = ((BaseUnityPlugin)this).Config.Bind<bool>("0.总开关", "失败后自动重新载入存档", true, "失败后等新场景生成完成,再重新载入当前存档"); ReloadDelaySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("0.总开关", "重新载入延迟秒数", 0.25f, "关卡生成完成后等待多久再重新载入存档"); BlockArenaPersistence = ((BaseUnityPlugin)this).Config.Bind<bool>("1.保护范围", "阻止竞技场删档保存", true, "游戏失败后通常会进入竞技场/结算流程,开启后阻止该阶段删档、重置进度和覆盖保存"); EnablePublicSaves = ((BaseUnityPlugin)this).Config.Bind<bool>("2.公开房存档", "允许公开房保存", true, "参考 PublicSaves:公开房退出到主菜单时也走正常保存,并阻止公开房删档"); EnablePublicGameContinueSave = ((BaseUnityPlugin)this).Config.Bind<bool>("2.公开房存档", "公开房继续当前存档", true, "参考 OnlineGameTweak:创建公开房时可以使用当前选择的存档继续进度,而不是强制新档"); ShowPingHud = ((BaseUnityPlugin)this).Config.Bind<bool>("3.联机显示", "显示实时 Ping", false, "参考 OnlineGameTweak:在游戏 HUD 上显示当前 Photon Ping"); EnableSameLevelRetry = ((BaseUnityPlugin)this).Config.Bind<bool>("4.同关重试", "死亡后重开同一关", false, "参考 JustRetryPlus:失败时拦截原始失败切图,直接重开当前关卡。开启后会替代自动重新载入存档流程"); RestoreRetryHealth = ((BaseUnityPlugin)this).Config.Bind<bool>("4.同关重试", "重试后恢复血量", true, "同关重试后恢复到本轮开始时记录的血量"); RestoreRetryMoney = ((BaseUnityPlugin)this).Config.Bind<bool>("4.同关重试", "重试后恢复金钱", true, "同关重试后恢复到本轮开始时记录的金钱"); RestoreRetryEnergy = ((BaseUnityPlugin)this).Config.Bind<bool>("4.同关重试", "重试后恢复充电站电量", true, "同关重试后恢复到本轮开始时记录的充电站电量"); RestoreRetryItemBatteries = ((BaseUnityPlugin)this).Config.Bind<bool>("4.同关重试", "重试后恢复道具电量", true, "同关重试后恢复本轮开始时记录的道具电池电量"); VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("9.调试", "显示详细日志", false, "开启后在 BepInEx 控制台打印被拦截的方法和联动功能细节"); } private void Update() { UpdatePingHud(); if (!EnableProtection.Value) { ClearProtectionState(startCooldown: false); _ignoreProtectionUntil = 0f; } else if (!_needsReload) { ClearProtectionAfterGeneratedWhenReloadDisabled(); } else if (!ReloadAfterFailure.Value) { ClearProtectionAfterGeneratedWhenReloadDisabled(); } else if (IsLevelGenerated()) { _reloadTimer += Time.deltaTime; if (!(_reloadTimer < Mathf.Max(0.01f, ReloadDelaySeconds.Value))) { TryReloadCurrentSave(); } } } private static void ClearProtectionAfterGeneratedWhenReloadDisabled() { if (!_retryInProgress && _blockSaves && !ReloadAfterFailure.Value && IsLevelGenerated()) { _reloadTimer += Time.deltaTime; if (!(_reloadTimer < Mathf.Max(0.01f, ReloadDelaySeconds.Value))) { ClearProtectionState(startCooldown: true); Log.LogInfo((object)"死亡不删档临时保存拦截已解除。"); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)_pingHudObject != (Object)null) { Object.Destroy((Object)(object)_pingHudObject); } } private static void BeginProtection(string reason) { if (!EnableProtection.Value) { return; } if (Time.unscaledTime < _ignoreProtectionUntil) { if (VerboseLogging.Value) { Log.LogInfo((object)("忽略重载后的重复失败流程: " + reason)); } } else if (_blockSaves || _needsReload) { if (VerboseLogging.Value && !string.Equals(_activeProtectionReason, reason, StringComparison.Ordinal)) { Log.LogInfo((object)("死亡不删档保护已在执行中,忽略重复流程: " + reason)); } } else { _blockSaves = true; _needsReload = ReloadAfterFailure.Value; _reloadTimer = 0f; _activeProtectionReason = reason; Log.LogInfo((object)("检测到失败流程,已启用死亡不删档保护: " + reason)); } } private static void ClearProtectionState(bool startCooldown) { _blockSaves = false; _needsReload = false; _reloadTimer = 0f; _activeProtectionReason = null; if (startCooldown) { _ignoreProtectionUntil = Time.unscaledTime + 2f; } } private static bool TryStartSameLevelRetry(RunManager runManager) { if (!EnableProtection.Value || (Object)(object)runManager == (Object)null) { return false; } if (Time.unscaledTime < _ignoreProtectionUntil) { return true; } if (_retryInProgress) { return true; } _blockSaves = true; _needsReload = false; _reloadTimer = 0f; _activeProtectionReason = "同关重试"; _retryInProgress = true; try { Log.LogInfo((object)"检测到失败流程,已启用同关重试保护。"); runManager.RestartScene(); return true; } catch (Exception ex) { _retryInProgress = false; _blockSaves = false; _activeProtectionReason = null; BeginProtection("同关重试失败,回退到存档保护"); Log.LogWarning((object)("同关重试启动失败,已回退到死亡不删档保护: " + ex.Message)); return false; } } private static bool ShouldBlockDangerousPersistence() { if (!EnableProtection.Value) { return false; } if (_blockSaves) { return true; } if (BlockArenaPersistence.Value) { return IsRunArenaSafe(); } return false; } private static bool ShouldProtectFailure(RunManager runManager) { if ((Object)(object)runManager == (Object)null) { return false; } Level val = ReadField<Level>(RunLevelCurrentField, runManager); if ((Object)(object)val == (Object)null) { return false; } if (IsSameLevel(val, ReadField<Level>(RunLevelLobbyField, runManager))) { return false; } if (IsSameLevel(val, ReadField<Level>(RunLevelLobbyMenuField, runManager))) { return false; } if (IsSameLevel(val, ReadField<Level>(RunLevelMainMenuField, runManager))) { return false; } if (IsSameLevel(val, ReadField<Level>(RunLevelTutorialField, runManager))) { return false; } if (IsSameLevel(val, ReadField<Level>(RunLevelRecordingField, runManager))) { return false; } if (IsLevelInList(val, ReadField<List<Level>>(RunLevelArenaField, runManager))) { return false; } try { if (SemiFunc.IsLevelShop(val)) { return false; } } catch { } return true; } private static bool IsSameLevel(Level left, Level right) { if ((Object)(object)left == (Object)null || (Object)(object)right == (Object)null) { return false; } return (Object)(object)left == (Object)(object)right; } private static bool IsLevelInList(Level level, List<Level> levels) { if ((Object)(object)level == (Object)null || levels == null) { return false; } for (int i = 0; i < levels.Count; i++) { if (IsSameLevel(level, levels[i])) { return true; } } return false; } private static bool IsRunArenaSafe() { try { return SemiFunc.RunIsArena(); } catch { return false; } } private static bool IsLevelGenerated() { object obj = ReadStaticField(LevelGeneratorInstanceField); if (obj == null) { return false; } return ReadBool(LevelGeneratorGeneratedField, obj); } private static void TryReloadCurrentSave() { StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null) { return; } string text = ReadField<string>(StatsSaveFileCurrentField, instance); if (string.IsNullOrWhiteSpace(text)) { Log.LogWarning((object)"无法重新载入存档:当前存档名为空。"); ClearProtectionState(startCooldown: true); return; } if (StatsLoadGameMethod == null) { Log.LogError((object)"无法重新载入存档:找不到 StatsManager.LoadGame。"); return; } try { _blockSaves = false; _ignoreProtectionUntil = Time.unscaledTime + 2f; StatsLoadGameMethod.Invoke(instance, new object[2] { text, null }); _needsReload = false; _reloadTimer = 0f; _activeProtectionReason = null; Log.LogInfo((object)("已重新载入存档: " + text)); } catch (Exception ex) { _blockSaves = true; _reloadTimer = 0f; Log.LogWarning((object)("重新载入存档失败,将稍后重试: " + ex.Message)); } } [IteratorStateMachine(typeof(<SaveRetryStateDelayed>d__62))] private static IEnumerator SaveRetryStateDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SaveRetryStateDelayed>d__62(0); } [IteratorStateMachine(typeof(<HandleRetryRestore>d__63))] private static IEnumerator HandleRetryRestore() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <HandleRetryRestore>d__63(0); } private static void RestoreRetryState() { if (!_hasRetrySnapshot) { Log.LogWarning((object)"没有可用的同关重试状态快照,本次只重开关卡,不恢复血量、金钱和电量。"); return; } if (RestoreRetryHealth.Value) { RestorePlayerHealth(); } if (RestoreRetryMoney.Value) { SetRunMoney(_savedMoney); } if (RestoreRetryEnergy.Value) { RestoreChargingStationState(); } if (RestoreRetryItemBatteries.Value) { RestoreItemBatteryCharges(); } } private static void SaveChargingStationState() { ChargingStation instance = ChargingStation.instance; if (!((Object)(object)instance == (Object)null)) { _savedChargeTotal = ReadIntField(AccessTools.Field(typeof(ChargingStation), "chargeTotal"), instance, _savedChargeTotal); } } private static void RestoreChargingStationState() { if (_savedChargeTotal >= 0) { StatsManager instance = StatsManager.instance; if ((Object)(object)instance != (Object)null && instance.runStats != null) { instance.runStats["chargingStationChargeTotal"] = _savedChargeTotal; } ChargingStation instance2 = ChargingStation.instance; if (!((Object)(object)instance2 == (Object)null)) { SetFieldValue(AccessTools.Field(typeof(ChargingStation), "chargeTotal"), instance2, _savedChargeTotal); SetFieldValue(AccessTools.Field(typeof(ChargingStation), "chargeFloat"), instance2, (float)_savedChargeTotal / 100f); SetFieldValue(AccessTools.Field(typeof(ChargingStation), "chargeSegmentCurrent"), instance2, Mathf.RoundToInt((float)_savedChargeTotal / 100f * 40f)); } } } private static int GetRunMoney() { StatsManager instance = StatsManager.instance; if ((Object)(object)instance == (Object)null || instance.runStats == null) { return 0; } if (!instance.runStats.TryGetValue("currency", out var value)) { return 0; } return value; } private static void SetRunMoney(int value) { StatsManager instance = StatsManager.instance; if (!((Object)(object)instance == (Object)null) && instance.runStats != null) { instance.runStats["currency"] = value; } } private static void RestorePlayerHealth() { if (_savedHealth <= 0) { return; } List<PlayerAvatar> list = SemiFunc.PlayerGetAll(); if (list == null) { return; } FieldInfo field = AccessTools.Field(typeof(PlayerHealth), "health"); FieldInfo field2 = AccessTools.Field(typeof(PlayerHealth), "maxHealth"); foreach (PlayerAvatar item in list) { PlayerHealth val = item?.playerHealth; if (!((Object)(object)val == (Object)null)) { int num = ReadIntField(field2, val, _savedHealth); SetFieldValue(field, val, Mathf.Clamp(_savedHealth, 1, Mathf.Max(1, num))); } } } private static void SaveItemBatteryCharges() { SavedItemCharges.Clear(); ItemBattery[] array = Object.FindObjectsOfType<ItemBattery>(); foreach (ItemBattery val in array) { FieldInfo fieldInfo = AccessTools.Field(((object)val).GetType(), "batteryLife"); if (!(fieldInfo == null)) { string batteryKey = GetBatteryKey(val); SavedItemCharges[batteryKey] = ReadFloatField(fieldInfo, val, 0f); } } } private static void RestoreItemBatteryCharges() { if (SavedItemCharges.Count == 0) { return; } ItemBattery[] array = Object.FindObjectsOfType<ItemBattery>(); foreach (ItemBattery val in array) { FieldInfo fieldInfo = AccessTools.Field(((object)val).GetType(), "batteryLife"); if (!(fieldInfo == null)) { string batteryKey = GetBatteryKey(val); if (SavedItemCharges.TryGetValue(batteryKey, out var value)) { SetFieldValue(fieldInfo, val, value); } } } } private static string GetBatteryKey(ItemBattery battery) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)battery).transform; return $"{((Object)((Component)battery).gameObject).name}_{transform.position}"; } private static void UpdatePingHud() { if (!ShowPingHud.Value || !SafeRunIsLevel()) { if ((Object)(object)_pingHudObject != (Object)null) { _pingHudObject.SetActive(false); } } else if (EnsurePingHud()) { int ping = PhotonNetwork.GetPing(); ((TMP_Text)_pingText).SetText($"Ping {ping}", true); _pingHudObject.SetActive(true); } } private static bool EnsurePingHud() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_pingHudObject != (Object)null && (Object)(object)_pingText != (Object)null) { return true; } GameObject val = GameObject.Find("Game Hud"); if ((Object)(object)val == (Object)null) { return false; } _pingHudObject = new GameObject("DeathNoSaveDelete Ping HUD"); _pingHudObject.SetActive(false); _pingHudObject.transform.SetParent(val.transform, false); _pingText = _pingHudObject.AddComponent<TextMeshProUGUI>(); TMP_Text val2 = null; GameObject val3 = GameObject.Find("Tax Haul"); if ((Object)(object)val3 != (Object)null) { val2 = val3.GetComponent<TMP_Text>(); } if ((Object)(object)val2 != (Object)null) { ((TMP_Text)_pingText).font = val2.font; } ((Graphic)_pingText).color = Color.cyan; ((TMP_Text)_pingText).fontSize = 24f; ((TMP_Text)_pingText).enableWordWrapping = false; ((TMP_Text)_pingText).alignment = (TextAlignmentOptions)260; RectTransform component = _pingHudObject.GetComponent<RectTransform>(); component.pivot = new Vector2(1f, 1f); component.anchorMin = new Vector2(1f, 0f); component.anchorMax = new Vector2(1f, 0f); component.anchoredPosition = new Vector2(-24f, 225f); component.sizeDelta = new Vector2(260f, 40f); return true; } private static bool SafeRunIsLevel() { try { return SemiFunc.RunIsLevel(); } catch { return false; } } private static bool TryHandlePublicGameHost(MenuPageServerListCreateNew page) { if (!EnablePublicGameContinueSave.Value || (Object)(object)page == (Object)null) { return false; } _hostedPublicGame = true; string value = ReadField<string>(MenuTextInputTextCurrentField, page.menuTextInput) ?? string.Empty; SetFieldValue(DataNetworkServerNameField, DataDirector.instance, value); SemiFunc.MainMenuSetMultiplayer(); MenuManager.instance.PageCloseAll(); MenuManager.instance.PageOpen((MenuPageIndex)11, false); Log.LogInfo((object)"已进入公开房存档选择流程。"); return true; } private static bool TryContinuePublicGame(ref string saveFileName, ref List<string> saveFileBackups) { if (!EnablePublicGameContinueSave.Value || !_hostedPublicGame) { return false; } _hostedPublicGame = false; RunManager.instance.ResetProgress(); if (!string.IsNullOrWhiteSpace(saveFileName)) { Log.LogInfo((object)("公开房继续存档: " + saveFileName)); SemiFunc.SaveFileLoad(saveFileName, saveFileBackups); } else { Log.LogInfo((object)"公开房创建新存档。"); SemiFunc.SaveFileCreate(); } GameManager.instance.localTest = false; SetFieldValue(RunWaitToChangeSceneField, RunManager.instance, true); RunManager.instance.ChangeLevel(true, false, (ChangeLevelType)3); GameManager.instance.SetConnectRandom(true); SetFieldValue(RunLobbyJoinField, RunManager.instance, true); return true; } private static bool IsPublicLobbySafe() { if (TryGetSingletonBool("GameManager", "instance", out var value, "connectRandom", "isConnectRandom", "quickJoin", "openLobby")) { return value; } if (TryGetStaticOrSingletonBool("NetworkConnect", out var value2, "connectRandom", "isConnectRandom")) { return value2; } if (TryGetStaticOrSingletonBool("NetworkController", out var value3, "connectRandom", "isConnectRandom")) { return value3; } return false; } private static int ReadIntField(FieldInfo field, object instance, int fallback) { if (field == null || instance == null) { return fallback; } try { return (field.GetValue(instance) is int num) ? num : fallback; } catch { return fallback; } } private static float ReadFloatField(FieldInfo field, object instance, float fallback) { if (field == null || instance == null) { return fallback; } try { return (field.GetValue(instance) is float num) ? num : fallback; } catch { return fallback; } } private static void SetFieldValue(FieldInfo field, object instance, object value) { if (field == null || instance == null) { return; } try { field.SetValue(instance, value); } catch (Exception ex) { if (VerboseLogging.Value) { Log.LogWarning((object)("写入字段失败 " + field.Name + ": " + ex.Message)); } } } private static bool TryGetSingletonBool(string typeName, string instanceMember, out bool value, params string[] candidates) { value = false; Type type = AccessTools.TypeByName(typeName); if (type == null) { return false; } object obj = null; FieldInfo fieldInfo = AccessTools.Field(type, instanceMember); if (fieldInfo != null) { obj = fieldInfo.GetValue(null); } if (obj == null) { PropertyInfo propertyInfo = AccessTools.Property(type, instanceMember); if (propertyInfo != null) { obj = propertyInfo.GetValue(null, null); } } if (obj == null) { return false; } foreach (string name in candidates) { if (TryGetBoolMember(obj, name, out value)) { return true; } } return false; } private static bool TryGetStaticOrSingletonBool(string typeName, out bool value, params string[] candidates) { value = false; Type type = AccessTools.TypeByName(typeName); if (type == null) { return false; } string[] array = candidates; foreach (string name in array) { if (TryGetStaticBoolMember(type, name, out value)) { return true; } } array = new string[3] { "Instance", "instance", "s_instance" }; foreach (string instanceMember in array) { if (TryGetSingletonBool(typeName, instanceMember, out value, candidates)) { return true; } } return false; } private static bool TryGetBoolMember(object instance, string name, out bool value) { value = false; if (instance == null) { return false; } Type type = instance.GetType(); FieldInfo fieldInfo = AccessTools.Field(type, name); if (fieldInfo != null && fieldInfo.FieldType == typeof(bool)) { value = (bool)fieldInfo.GetValue(instance); return true; } PropertyInfo propertyInfo = AccessTools.Property(type, name); if (propertyInfo != null && propertyInfo.PropertyType == typeof(bool)) { value = (bool)propertyInfo.GetValue(instance, null); return true; } return false; } private static bool TryGetStaticBoolMember(Type type, string name, out bool value) { value = false; FieldInfo fieldInfo = AccessTools.Field(type, name); if (fieldInfo != null && fieldInfo.IsStatic && fieldInfo.FieldType == typeof(bool)) { value = (bool)fieldInfo.GetValue(null); return true; } PropertyInfo propertyInfo = AccessTools.Property(type, name); if (propertyInfo != null && propertyInfo.GetMethod != null && propertyInfo.GetMethod.IsStatic && propertyInfo.PropertyType == typeof(bool)) { value = (bool)propertyInfo.GetValue(null, null); return true; } return false; } private static T ReadField<T>(FieldInfo field, object instance) where T : class { if (field == null || instance == null) { return null; } try { return field.GetValue(instance) as T; } catch { return null; } } private static object ReadStaticField(FieldInfo field) { if (field == null) { return null; } try { return field.GetValue(null); } catch { return null; } } private static bool ReadBool(FieldInfo field, object instance) { if (field == null || instance == null) { return false; } try { object value = field.GetValue(instance); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return false; } } private static bool AllowOriginalOrLog(string methodName) { bool num = ShouldBlockDangerousPersistence(); if (num && VerboseLogging.Value) { Log.LogInfo((object)("已拦截 " + methodName)); } return !num; } }