using System; 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 Microsoft.CodeAnalysis; 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("BetterNoRevivePenalty")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetterNoRevivePenalty")] [assembly: AssemblyTitle("BetterNoRevivePenalty")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 BetterNoRevivePenalty { [BepInPlugin("BetterNoRevivePenalty", "BetterNoRevivePenalty", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string GUID = "BetterNoRevivePenalty"; public const string NAME = "BetterNoRevivePenalty"; public const string VERSION = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry BlockCurse; internal static ConfigEntry BlockHunger; internal static int CurseIndex = -1; internal static int HungerIndex = -1; internal static int ReviveScopeDepth; internal static int VoidEntryDepth; internal static bool BlockingAtSource; internal static bool InReviveScope { get { if (ReviveScopeDepth > 0) { return VoidEntryDepth == 0; } return false; } } internal static bool ShouldBlock(int statusIndex) { if (!InReviveScope) { return false; } if (statusIndex == CurseIndex) { if (BlockCurse != null) { return BlockCurse.Value; } return false; } if (statusIndex == HungerIndex) { if (BlockHunger != null) { return BlockHunger.Value; } return false; } return false; } private void Awake() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; BlockCurse = ((BaseUnityPlugin)this).Config.Bind("Revive Penalty", "Block Curse", true, "Prevent the Curse applied by being revived. Curse from every other source is untouched."); BlockHunger = ((BaseUnityPlugin)this).Config.Bind("Revive Penalty", "Block Hunger", false, "Also prevent the Hunger applied by being revived. Vanilla adds 30%."); CurseIndex = ResolveStatus("Curse"); HungerIndex = ResolveStatus("Hunger"); try { Install(new Harmony("BetterNoRevivePenalty")); } catch (Exception ex) { Log.LogError((object)("Patching failed. The mod is inert but the game is untouched: " + ex)); } } private void LateUpdate() { if (ReviveScopeDepth != 0) { ReviveScopeDepth = 0; } if (VoidEntryDepth != 0) { VoidEntryDepth = 0; } } private static int ResolveStatus(string name) { try { return (int)Enum.Parse(typeof(STATUSTYPE), name); } catch (Exception) { Log.LogWarning((object)("STATUSTYPE." + name + " no longer exists - that penalty will not be blocked.")); return -1; } } private static void Install(Harmony harmony) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00b0: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0124: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Character), "ApplyPostReviveStatus", (Type[])null, (Type[])null); bool flag = methodInfo != null; if (methodInfo == null) { methodInfo = AccessTools.Method(typeof(Character), "ReviveCharacter", (Type[])null, (Type[])null); if (methodInfo != null) { Log.LogWarning((object)"Character.ApplyPostReviveStatus is gone; scoping Character.ReviveCharacter instead."); } } if (methodInfo == null) { Log.LogError((object)"Found no revive method to scope - mod has no effect. PEAK probably renamed it."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(ReviveScope), "Enter", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(ReviveScope), "Exit", (Type[])null, (Type[])null)), (HarmonyMethod)null); TryExcludeVoidEntry(harmony); BlockingAtSource = TryBlockAtSource(harmony); if (BlockingAtSource) { Log.LogInfo((object)"Ready. Revive penalties are blocked at CharacterAfflictions.AddStatus."); } else if (flag && SnapshotRestore.TargetIsCompatible(methodInfo)) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(SnapshotRestore), "Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.Method(typeof(SnapshotRestore), "Postfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogWarning((object)"CharacterAfflictions.AddStatus changed shape; using the snapshot/restore fallback."); } else { Log.LogError((object)"Neither strategy is available - mod has no effect, but revives still work normally."); } } private static void TryExcludeVoidEntry(Harmony harmony) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0083: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(MapHandler), "GoToVoidRoutine", (Type[])null, (Type[])null); MethodInfo methodInfo2 = ((methodInfo != null) ? AccessTools.EnumeratorMoveNext((MethodBase)methodInfo) : null); if (methodInfo2 == null) { Log.LogWarning((object)"Could not scope MapHandler.GoToVoidRoutine; entering the Void will have its curse blocked too."); } else { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(AccessTools.Method(typeof(VoidEntryScope), "Enter", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(VoidEntryScope), "Exit", (Type[])null, (Type[])null)), (HarmonyMethod)null); } } private static bool TryBlockAtSource(Harmony harmony) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(CharacterAfflictions), "AddStatus", (Type[])null, (Type[])null); if (methodInfo == null) { return false; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length < 1 || parameters[0].ParameterType != typeof(STATUSTYPE)) { return false; } if (methodInfo.ReturnType != typeof(bool)) { return false; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(BlockStatus), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return true; } } internal static class ReviveScope { public static void Enter() { Plugin.ReviveScopeDepth++; } public static void Exit() { if (Plugin.ReviveScopeDepth > 0) { Plugin.ReviveScopeDepth--; } } } internal static class VoidEntryScope { public static void Enter() { Plugin.VoidEntryDepth++; } public static void Exit() { if (Plugin.VoidEntryDepth > 0) { Plugin.VoidEntryDepth--; } } } internal static class BlockStatus { public static bool Prefix(STATUSTYPE __0, ref bool __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected I4, but got Unknown if (!Plugin.ShouldBlock((int)__0)) { return true; } __result = false; return false; } } internal static class SnapshotRestore { public static bool TargetIsCompatible(MethodInfo target) { ParameterInfo[] parameters = target.GetParameters(); if (parameters.Length >= 1) { return parameters[0].ParameterType == typeof(CharacterAfflictions); } return false; } public static void Prefix(CharacterAfflictions __0, out float[] __state) { __state = null; float[] array = (((Object)(object)__0 != (Object)null) ? __0.currentStatuses : null); if (array != null) { __state = new float[2]; __state[0] = Read(array, Plugin.CurseIndex); __state[1] = Read(array, Plugin.HungerIndex); } } public static void Postfix(CharacterAfflictions __0, float[] __state) { if (__state != null && !((Object)(object)__0 == (Object)null) && __0.currentStatuses != null) { if (Plugin.BlockCurse.Value) { Write(__0.currentStatuses, Plugin.CurseIndex, __state[0]); } if (Plugin.BlockHunger.Value) { Write(__0.currentStatuses, Plugin.HungerIndex, __state[1]); } } } private static float Read(float[] statuses, int index) { if (index < 0 || index >= statuses.Length) { return 0f; } return statuses[index]; } private static void Write(float[] statuses, int index, float value) { if (index >= 0 && index < statuses.Length) { statuses[index] = value; } } } }