Decompiled source of InfiniteManual v1.0.0

InfiniteManual.dll

Decompiled 2 days ago
using System;
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 Reptile;
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("InfiniteManual")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("InfiniteManual")]
[assembly: AssemblyTitle("InfiniteManual")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace InfiniteManual;

internal static class ManualPatches
{
	internal const int TotalPatches = 3;

	private static ManualLogSource log;

	private static FieldRef<Player, Ability> abilityRef;

	private static FieldRef<Player, SlideAbility> slideAbilityRef;

	private static FieldRef<Player, bool> isAIRef;

	private static FieldRef<Player, GameplayUI> uiRef;

	private static FieldRef<Player, float> showLastScoreTimerRef;

	private static readonly HashSet<string> reportedErrors = new HashSet<string>();

	internal static int Apply(Harmony harmony, ManualLogSource logger)
	{
		log = logger;
		try
		{
			abilityRef = AccessTools.FieldRefAccess<Player, Ability>("ability");
			slideAbilityRef = AccessTools.FieldRefAccess<Player, SlideAbility>("slideAbility");
			isAIRef = AccessTools.FieldRefAccess<Player, bool>("isAI");
			uiRef = AccessTools.FieldRefAccess<Player, GameplayUI>("ui");
			showLastScoreTimerRef = AccessTools.FieldRefAccess<Player, float>("showLastScoreTimer");
		}
		catch (Exception ex)
		{
			log.LogError((object)("Could not resolve required Player fields (game update changed them?). No patches applied; the game runs unmodified. Details: " + ex));
			return 0;
		}
		int num = 0;
		bool num2 = TryPatch(harmony, typeof(SlideAbility), "FixedUpdateAbility", null, "SlideAbility_FixedUpdateAbility_Postfix");
		bool flag = TryPatch(harmony, typeof(SlideAbility), "ComboTimeout", "SlideAbility_ComboTimeout_Prefix", null);
		bool flag2 = TryPatch(harmony, typeof(Player), "ScoreDisplayUpdate", null, "Player_ScoreDisplayUpdate_Postfix");
		if (num2)
		{
			num++;
		}
		if (flag)
		{
			num++;
		}
		if (flag2)
		{
			num++;
		}
		if (!num2)
		{
			log.LogWarning((object)"Without the FixedUpdateAbility patch the meter will still drain during manuals.");
		}
		if (!flag)
		{
			log.LogWarning((object)"Without the ComboTimeout patch a manual can still end when the meter empties.");
		}
		if (!flag2)
		{
			log.LogWarning((object)"Without the ScoreDisplayUpdate patch the HUD bar is hidden (vanilla) instead of shown full.");
		}
		return num;
	}

	private static bool TryPatch(Harmony harmony, Type type, string methodName, string prefix, string postfix)
	{
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		string text = type.Name + "." + methodName;
		try
		{
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, methodName, Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				log.LogError((object)("Patch FAILED: " + text + "() not found in Assembly-CSharp."));
				return false;
			}
			HarmonyMethod val = ((prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(ManualPatches), prefix, (Type[])null));
			HarmonyMethod val2 = ((postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(ManualPatches), postfix, (Type[])null));
			harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			log.LogInfo((object)("Patched " + text + " (" + ((prefix != null) ? "prefix" : "postfix") + ")."));
			return true;
		}
		catch (Exception arg)
		{
			log.LogError((object)$"Patch FAILED: {text}: {arg}");
			return false;
		}
	}

	private static bool IsLocalPlayerInManual(Player p)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Invalid comparison between Unknown and I4
		if ((Object)(object)p == (Object)null)
		{
			return false;
		}
		if (isAIRef.Invoke(p))
		{
			return false;
		}
		SlideAbility val = slideAbilityRef.Invoke(p);
		if (val == null)
		{
			return false;
		}
		if ((object)abilityRef.Invoke(p) != val)
		{
			return false;
		}
		if (!val.IsPerformingManual)
		{
			return false;
		}
		return (int)val.slideState != 4;
	}

	private static void SlideAbility_FixedUpdateAbility_Postfix(SlideAbility __instance)
	{
		try
		{
			if (InfiniteManualPlugin.KeepMeterFull && __instance != null)
			{
				Player p = ((Ability)__instance).p;
				if (IsLocalPlayerInManual(p))
				{
					p.RefillComboTimeOut();
				}
			}
		}
		catch (Exception e)
		{
			ReportOnce("FixedUpdateAbility", e);
		}
	}

	private static bool SlideAbility_ComboTimeout_Prefix(SlideAbility __instance)
	{
		try
		{
			if (!InfiniteManualPlugin.Active || __instance == null)
			{
				return true;
			}
			if (IsLocalPlayerInManual(((Ability)__instance).p))
			{
				return false;
			}
		}
		catch (Exception e)
		{
			ReportOnce("ComboTimeout", e);
		}
		return true;
	}

	private static void Player_ScoreDisplayUpdate_Postfix(Player __instance)
	{
		try
		{
			if (!InfiniteManualPlugin.KeepMeterFull || !IsLocalPlayerInManual(__instance) || showLastScoreTimerRef.Invoke(__instance) > 0f || !__instance.IsComboing())
			{
				return;
			}
			GameplayUI val = uiRef.Invoke(__instance);
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val.comboTimeOutBar != (Object)null)
				{
					val.comboTimeOutBar.fillAmount = 1f;
				}
				if ((Object)(object)val.comboTimeOutBackdrop != (Object)null)
				{
					val.comboTimeOutBackdrop.fillAmount = 1f;
				}
			}
		}
		catch (Exception e)
		{
			ReportOnce("ScoreDisplayUpdate", e);
		}
	}

	private static void ReportOnce(string where, Exception e)
	{
		if (reportedErrors.Add(where))
		{
			ManualLogSource obj = log;
			if (obj != null)
			{
				obj.LogError((object)$"Exception in {where} patch (further errors from this patch are suppressed): {e}");
			}
		}
	}
}
[BepInPlugin("brc.infinitemanual", "InfiniteManual", "1.0.0")]
[BepInProcess("Bomb Rush Cyberfunk.exe")]
public sealed class InfiniteManualPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "brc.infinitemanual";

	public const string PluginName = "InfiniteManual";

	public const string PluginVersion = "1.0.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> EnabledConfig;

	internal static ConfigEntry<bool> KeepMeterFullConfig;

	internal static ConfigEntry<KeyboardShortcut> ToggleKeyConfig;

	internal static bool RuntimeEnabled;

	private Harmony harmony;

	private string toastText;

	private float toastUntil;

	internal static bool Active => RuntimeEnabled;

	internal static bool KeepMeterFull
	{
		get
		{
			if (RuntimeEnabled && KeepMeterFullConfig != null)
			{
				return KeepMeterFullConfig.Value;
			}
			return false;
		}
	}

	private void Awake()
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Expected O, but got Unknown
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		EnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Mod is on when the game starts.");
		KeepMeterFullConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "KeepMeterFull", true, "Keep the manual meter full.");
		ToggleKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Key to turn the mod on/off.");
		RuntimeEnabled = EnabledConfig.Value;
		EnabledConfig.SettingChanged += delegate
		{
			SetEnabled(EnabledConfig.Value, "config");
		};
		harmony = new Harmony("brc.infinitemanual");
		int num = ManualPatches.Apply(harmony, Log);
		Log.LogInfo((object)(string.Format("{0} {1} loaded: {2}/{3} patches applied. ", "InfiniteManual", "1.0.0", num, 3) + $"Enabled={RuntimeEnabled}, KeepMeterFull={KeepMeterFullConfig.Value}, ToggleKey={ToggleKeyConfig.Value}"));
	}

	private void Update()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (ToggleKeyConfig != null)
		{
			KeyboardShortcut value = ToggleKeyConfig.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				SetEnabled(!RuntimeEnabled, "hotkey");
			}
		}
	}

	private void SetEnabled(bool value, string source)
	{
		if (RuntimeEnabled != value)
		{
			RuntimeEnabled = value;
			string text = "InfiniteManual " + (value ? "ON" : "OFF");
			Log.LogInfo((object)(text + " (via " + source + ")"));
			toastText = text;
			toastUntil = Time.unscaledTime + 2f;
		}
	}

	private void OnGUI()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		if (toastText != null && !(Time.unscaledTime > toastUntil))
		{
			GUI.Label(new Rect(20f, 20f, 400f, 30f), toastText);
		}
	}

	private void OnDestroy()
	{
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}
}