Decompiled source of BetterNoRevivePenalty v1.0.0

BetterNoRevivePenalty.dll

Decompiled 17 hours ago
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<bool> BlockCurse;

		internal static ConfigEntry<bool> 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<bool>("Revive Penalty", "Block Curse", true, "Prevent the Curse applied by being revived. Curse from every other source is untouched.");
			BlockHunger = ((BaseUnityPlugin)this).Config.Bind<bool>("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;
			}
		}
	}
}