Decompiled source of LimitBypassMod v1.5.5

LimitBypassMod.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OpenShot.Core;
using OpenShot.Events;
using OpenShot.UI;
using Shooterlatro.Core;
using Shooterlatro.Game;
using Shooterlatro.Shop;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LimitBypassMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bypasses integer limits using BigInteger shadow state.")]
[assembly: AssemblyFileVersion("1.5.5.0")]
[assembly: AssemblyInformationalVersion("1.5.5+4135dd1490a61fe647f2a0e54287f36471f5cf7f")]
[assembly: AssemblyProduct("LimitBypassMod")]
[assembly: AssemblyTitle("LimitBypassMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.5.0")]
[module: UnverifiableCode]
[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 LimitBypassMod
{
	public static class ConsoleCommands
	{
		[ConsoleCommand("limit_bypass_max_stats", "Sets all resources and score to 9 quintillion (LimitBypassMod).")]
		public static void MaxStatsCommand()
		{
			ShadowState.TotalTargetsDestroyed = (ShadowState.TotalScore = (ShadowState.Currency = BigInteger.Parse("9223372036854775807")));
			LimitBypassPlugin.Log.LogInfo((object)"LimitBypassMod: Stats maxed via console!");
		}

		[ConsoleCommand("limit_bypass_max_ammo", "Sets all ammo pools to 50 billion (LimitBypassMod).")]
		public static void MaxAmmoCommand()
		{
			BigInteger value = BigInteger.Parse("52147483637");
			ShadowState.AmmoPools["Normal"] = value;
			ShadowState.CurrentAmmo["Normal"] = value;
			ShadowState.AmmoPools["Rainbow"] = value;
			ShadowState.CurrentAmmo["Rainbow"] = value;
			ShadowState.AmmoPools["Clone"] = value;
			ShadowState.CurrentAmmo["Clone"] = value;
			ShadowState.AmmoPools["Shiny"] = value;
			ShadowState.CurrentAmmo["Shiny"] = value;
			ShadowState.IsAmmoDirty = true;
			LimitBypassPlugin.Log.LogInfo((object)"LimitBypassMod: Ammo pools maxed via console!");
		}
	}
	public static class LimitBypassDecisionAPI
	{
		public static bool CanAffordCurrency(int basePrice, int multiplier = 1)
		{
			BigInteger bigInteger = new BigInteger(basePrice) * new BigInteger(multiplier);
			return ShadowState.Currency >= bigInteger;
		}

		public static void ConsumeCurrency(int basePrice, int multiplier = 1)
		{
			BigInteger bigInteger = new BigInteger(basePrice) * new BigInteger(multiplier);
			if (ShadowState.Currency >= bigInteger)
			{
				ShadowState.Currency -= bigInteger;
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.luckyshot.limitbypass", "Limit Bypass Mod", "1.5.5")]
	public class LimitBypassPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.luckyshot.limitbypass";

		public const string PluginName = "Limit Bypass Mod";

		public const string PluginVersion = "1.5.5";

		public static ManualLogSource Log { get; private set; }

		public static ConfigEntry<bool> Enabled { get; private set; }

		public static ConfigEntry<bool> InfiniteAmmo { get; private set; }

		public static ConfigEntry<bool> AutoRefillMagazine { get; private set; }

		public static ConfigEntry<bool> TrackShadowAmmo { get; private set; }

		public static ConfigEntry<bool> OverrideHugeUi { get; private set; }

		public static ConfigEntry<bool> TmpAutoSizeFix { get; private set; }

		public static ConfigEntry<int> ShadowShopThreshold { get; private set; }

		public static ConfigEntry<int> DisplayOverrideThreshold { get; private set; }

		public static bool Active
		{
			get
			{
				if (Enabled != null)
				{
					return Enabled.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			BindAndRegisterMenu();
			new GameObject("LimitBypass_StringFormatter").AddComponent<StringFormatter>();
			new Harmony("com.luckyshot.limitbypass").PatchAll();
			OpenShotEventHandlers.Initialize();
			Log.LogInfo((object)"Limit Bypass Mod v1.5.5 loaded (OpenShot 2.0.3).");
		}

		private void BindAndRegisterMenu()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for Limit Bypass behaviour.");
			InfiniteAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "InfiniteAmmo", true, "Force Weapon.HasInfiniteAmmo = true.");
			AutoRefillMagazine = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "AutoRefillMagazine", true, "Auto-refill magazine from shadow reserves.");
			TrackShadowAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "TrackShadowAmmo", true, "Decrement shadow ammo pools on shots.");
			OverrideHugeUi = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "OverrideHugeUi", true, "Rewrite money/ticket/ammo UI when values are huge.");
			TmpAutoSizeFix = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "TmpAutoSizeFix", true, "Auto-size TMP for very long number strings.");
			ShadowShopThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "ShadowShopThreshold", 1000000, new ConfigDescription("Costs above this use shadow BigInteger afford checks.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100000, 10000000), Array.Empty<object>()));
			DisplayOverrideThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "DisplayOverrideThreshold", 2000000000, new ConfigDescription("UI override kicks in above this int value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100000000, 2000000000), Array.Empty<object>()));
			ModMenu.Tab("Limit Bypass").Toggle(Enabled).Info("— Ammo —")
				.Bool("Infinite Ammo", InfiniteAmmo)
				.Bool("Auto Refill Mag", AutoRefillMagazine)
				.Bool("Track Shadow Ammo", TrackShadowAmmo)
				.Info("— Shop / UI —")
				.Int("Shop Threshold", ShadowShopThreshold, 100000)
				.Bool("Huge UI Override", OverrideHugeUi)
				.Int("UI Threshold", DisplayOverrideThreshold, 100000000)
				.Bool("TMP Auto Size", TmpAutoSizeFix)
				.Info("— Cheats —")
				.Button("Max Stats", (Action)ConsoleCommands.MaxStatsCommand)
				.Button("Max Ammo", (Action)ConsoleCommands.MaxAmmoCommand);
		}
	}
	[HarmonyPatch(typeof(GameEvents), "PublishShotFired")]
	public static class GameEvents_PublishShotFired_Patch
	{
		private static int _bulletsBeforeShot;

		private static void Prefix()
		{
			_bulletsBeforeShot = GetTotalBulletsFired();
		}

		private static void Postfix()
		{
			if (!LimitBypassPlugin.Active || !LimitBypassPlugin.TrackShadowAmmo.Value)
			{
				return;
			}
			int num = GetTotalBulletsFired() - _bulletsBeforeShot;
			if (num > 0)
			{
				ShadowState.TotalBulletsFired += (BigInteger)num;
				if (ShadowState.CurrentAmmo.ContainsKey("Rainbow") && ShadowState.CurrentAmmo["Rainbow"] >= num)
				{
					ShadowState.CurrentAmmo["Rainbow"] -= (BigInteger)num;
					ShadowState.IsAmmoDirty = true;
				}
				else if (ShadowState.CurrentAmmo.ContainsKey("Normal") && ShadowState.CurrentAmmo["Normal"] >= num)
				{
					ShadowState.CurrentAmmo["Normal"] -= (BigInteger)num;
					ShadowState.IsAmmoDirty = true;
				}
			}
		}

		private static int GetTotalBulletsFired()
		{
			GameManager val = Object.FindObjectOfType<GameManager>();
			if (!((Object)(object)val != (Object)null))
			{
				return 0;
			}
			return val.TotalBulletsFired;
		}
	}
	[HarmonyPatch(typeof(ShopManager), "TryPurchase")]
	public static class ShopManager_TryPurchase_Patch
	{
		private static bool Prefix(ShopItem item, ref bool __result)
		{
			if (!LimitBypassPlugin.Active)
			{
				return true;
			}
			int num = ((item != null) ? Mathf.RoundToInt(item.cost) : 0);
			if (num > LimitBypassPlugin.ShadowShopThreshold.Value)
			{
				__result = LimitBypassDecisionAPI.CanAffordCurrency(num);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class Weapon_HasInfiniteAmmo_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("Shooterlatro.Weapons.Weapon"), "get_HasInfiniteAmmo", (Type[])null, (Type[])null);
		}

		private static bool Prefix(ref bool __result)
		{
			if (!LimitBypassPlugin.Active || !LimitBypassPlugin.InfiniteAmmo.Value)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	public static class OpenShotEventHandlers
	{
		public static bool IsModRefilling;

		private static BigInteger UiThreshold => new BigInteger(LimitBypassPlugin.DisplayOverrideThreshold?.Value ?? 2000000000);

		public static void Initialize()
		{
			GameEvents.OnWeaponReloaded += OnWeaponReloaded;
			GameEvents.OnMoneyAmountChanged += OnMoneyAmountChanged;
			GameEvents.OnTicketAmountChanged += OnTicketAmountChanged;
			GameEvents.OnAmmoDisplayUpdated += OnAmmoDisplayUpdated;
		}

		private static void OnWeaponReloaded(object weapon, int amount, ref bool cancel)
		{
			if (!LimitBypassPlugin.Active || !LimitBypassPlugin.TrackShadowAmmo.Value || IsModRefilling || weapon == null)
			{
				return;
			}
			Traverse obj = Traverse.Create(weapon);
			int value = obj.Property("CurrentAmmo", (object[])null).GetValue<int>();
			int num = obj.Property("MaxAmmo", (object[])null).GetValue<int>() - value;
			if (amount >= num && num > 0)
			{
				foreach (KeyValuePair<string, BigInteger> ammoPool in ShadowState.AmmoPools)
				{
					ShadowState.CurrentAmmo[ammoPool.Key] = ammoPool.Value;
				}
			}
			else
			{
				if (ShadowState.CurrentAmmo.ContainsKey("Normal"))
				{
					ShadowState.CurrentAmmo["Normal"] += (BigInteger)amount;
					if (ShadowState.CurrentAmmo["Normal"] > ShadowState.AmmoPools["Normal"])
					{
						ShadowState.CurrentAmmo["Normal"] = ShadowState.AmmoPools["Normal"];
					}
				}
				foreach (KeyValuePair<string, BigInteger> ammoPool2 in ShadowState.AmmoPools)
				{
					if (ammoPool2.Key != "Normal")
					{
						ShadowState.CurrentAmmo[ammoPool2.Key] = ammoPool2.Value;
					}
				}
			}
			ShadowState.IsAmmoDirty = true;
		}

		private static void OnMoneyAmountChanged(object view)
		{
			if (LimitBypassPlugin.Active && LimitBypassPlugin.OverrideHugeUi.Value)
			{
				TMP_Text value = Traverse.Create(view).Field("_text").GetValue<TMP_Text>();
				if ((Object)(object)value != (Object)null && ShadowState.Currency > UiThreshold)
				{
					value.text = StringFormatter.Instance.CachedCurrencyString;
				}
			}
		}

		private static void OnTicketAmountChanged(object view)
		{
			if (LimitBypassPlugin.Active && LimitBypassPlugin.OverrideHugeUi.Value)
			{
				TMP_Text value = Traverse.Create(view).Field("_text").GetValue<TMP_Text>();
				if ((Object)(object)value != (Object)null && ShadowState.TotalTargetsDestroyed > UiThreshold)
				{
					value.text = StringFormatter.Instance.CachedTargetsString;
				}
			}
		}

		private static void OnAmmoDisplayUpdated(object view)
		{
			if (!LimitBypassPlugin.Active || !LimitBypassPlugin.OverrideHugeUi.Value)
			{
				return;
			}
			TMP_Text value = Traverse.Create(view).Field("bulletCountText").GetValue<TMP_Text>();
			if ((Object)(object)value == (Object)null)
			{
				return;
			}
			List<object> value2 = Traverse.Create(view).Field("_renderedMagazine").GetValue<List<object>>();
			if (value2 != null && value2.Count > 0)
			{
				string value3 = Traverse.Create(value2[0]).Property("name", (object[])null).GetValue<string>();
				if (value3 != null && ShadowState.CurrentAmmo.ContainsKey(value3) && ShadowState.CurrentAmmo[value3] > UiThreshold)
				{
					value.text = StringFormatter.Instance.GetAmmoString(value3);
				}
			}
			else if (ShadowState.CurrentAmmo.ContainsKey("Normal") && ShadowState.CurrentAmmo["Normal"] > UiThreshold)
			{
				value.text = StringFormatter.Instance.GetAmmoString("Normal");
			}
		}
	}
	public static class ShadowState
	{
		private static BigInteger _totalTargetsDestroyed = 0;

		private static BigInteger _totalBulletsFired = 0;

		private static BigInteger _totalScore = 0;

		private static BigInteger _currency = 0;

		public static bool IsTargetsDirty { get; private set; } = true;

		public static bool IsBulletsDirty { get; private set; } = true;

		public static bool IsScoreDirty { get; private set; } = true;

		public static bool IsCurrencyDirty { get; private set; } = true;

		public static BigInteger TotalTargetsDestroyed
		{
			get
			{
				return _totalTargetsDestroyed;
			}
			set
			{
				_totalTargetsDestroyed = value;
				IsTargetsDirty = true;
			}
		}

		public static BigInteger TotalBulletsFired
		{
			get
			{
				return _totalBulletsFired;
			}
			set
			{
				_totalBulletsFired = value;
				IsBulletsDirty = true;
			}
		}

		public static BigInteger TotalScore
		{
			get
			{
				return _totalScore;
			}
			set
			{
				_totalScore = value;
				IsScoreDirty = true;
			}
		}

		public static BigInteger Currency
		{
			get
			{
				return _currency;
			}
			set
			{
				_currency = value;
				IsCurrencyDirty = true;
			}
		}

		public static Dictionary<string, BigInteger> AmmoPools { get; } = new Dictionary<string, BigInteger>();

		public static Dictionary<string, BigInteger> CurrentAmmo { get; } = new Dictionary<string, BigInteger>();

		public static bool IsAmmoDirty { get; set; } = true;

		public static void ClearTargetsDirty()
		{
			IsTargetsDirty = false;
		}

		public static void ClearBulletsDirty()
		{
			IsBulletsDirty = false;
		}

		public static void ClearScoreDirty()
		{
			IsScoreDirty = false;
		}

		public static void ClearCurrencyDirty()
		{
			IsCurrencyDirty = false;
		}

		public static void ResetState()
		{
			TotalTargetsDestroyed = 0;
			TotalBulletsFired = 0;
			TotalScore = 0;
			Currency = 0;
			AmmoPools.Clear();
			CurrentAmmo.Clear();
			IsAmmoDirty = true;
		}
	}
	public class StringFormatter : MonoBehaviour
	{
		public static StringFormatter Instance { get; private set; }

		public string CachedTargetsString { get; private set; } = "0";

		public string CachedBulletsString { get; private set; } = "0";

		public string CachedScoreString { get; private set; } = "0";

		public string CachedCurrencyString { get; private set; } = "0";

		public Dictionary<string, string> CachedAmmoStrings { get; } = new Dictionary<string, string>();

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			FormatAll();
		}

		private void LateUpdate()
		{
			if (ShadowState.IsTargetsDirty)
			{
				CachedTargetsString = FormatBigInt(ShadowState.TotalTargetsDestroyed);
				ShadowState.ClearTargetsDirty();
			}
			if (ShadowState.IsBulletsDirty)
			{
				CachedBulletsString = FormatBigInt(ShadowState.TotalBulletsFired);
				ShadowState.ClearBulletsDirty();
			}
			if (ShadowState.IsScoreDirty)
			{
				CachedScoreString = FormatBigInt(ShadowState.TotalScore);
				ShadowState.ClearScoreDirty();
			}
			if (ShadowState.IsCurrencyDirty)
			{
				CachedCurrencyString = FormatBigInt(ShadowState.Currency);
				ShadowState.ClearCurrencyDirty();
			}
			if (!ShadowState.IsAmmoDirty)
			{
				return;
			}
			CachedAmmoStrings.Clear();
			foreach (KeyValuePair<string, BigInteger> item in ShadowState.CurrentAmmo)
			{
				CachedAmmoStrings[item.Key] = FormatBigInt(item.Value);
			}
			ShadowState.IsAmmoDirty = false;
		}

		public void FormatAll()
		{
			CachedTargetsString = FormatBigInt(ShadowState.TotalTargetsDestroyed);
			CachedBulletsString = FormatBigInt(ShadowState.TotalBulletsFired);
			CachedScoreString = FormatBigInt(ShadowState.TotalScore);
			CachedCurrencyString = FormatBigInt(ShadowState.Currency);
			CachedAmmoStrings.Clear();
			foreach (KeyValuePair<string, BigInteger> item in ShadowState.CurrentAmmo)
			{
				CachedAmmoStrings[item.Key] = FormatBigInt(item.Value);
			}
			ShadowState.IsAmmoDirty = false;
		}

		public string GetAmmoString(string bulletType)
		{
			if (CachedAmmoStrings.TryGetValue(bulletType, out var value))
			{
				return value;
			}
			return "0";
		}

		private string FormatBigInt(BigInteger value)
		{
			if (value > new BigInteger(1000000000000000000L))
			{
				return value.ToString("E3");
			}
			return value.ToString("N0");
		}
	}
	[HarmonyPatch]
	public static class TMP_Text_set_text_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.PropertySetter(typeof(TMP_Text), "text");
		}

		private static void Postfix(TMP_Text __instance)
		{
			if (LimitBypassPlugin.Active && LimitBypassPlugin.TmpAutoSizeFix.Value && !((Object)(object)__instance == (Object)null) && !string.IsNullOrEmpty(__instance.text) && __instance.text.Length > 9 && (__instance.text.Contains("B") || __instance.text.Contains("E") || __instance.text.Length > 12))
			{
				__instance.enableAutoSizing = true;
				if (__instance.fontSizeMin > 10f)
				{
					__instance.fontSizeMin = 5f;
				}
				__instance.textWrappingMode = (TextWrappingModes)0;
				__instance.overflowMode = (TextOverflowModes)3;
			}
		}
	}
	[HarmonyPatch]
	public static class Weapon_Update_Patch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("Weapon"), "Update", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			if (!LimitBypassPlugin.Active || !LimitBypassPlugin.AutoRefillMagazine.Value || __instance == null)
			{
				return;
			}
			Traverse val = Traverse.Create(__instance);
			int value = val.Property("CurrentAmmo", (object[])null).GetValue<int>();
			int value2 = val.Property("MaxAmmo", (object[])null).GetValue<int>();
			if (value >= value2)
			{
				return;
			}
			bool flag = false;
			foreach (BigInteger value3 in ShadowState.CurrentAmmo.Values)
			{
				if (value3 > 0L)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return;
			}
			int num = value2 - value;
			OpenShotEventHandlers.IsModRefilling = true;
			try
			{
				val.Method("AddNormalBulletsToMagazine", new object[1] { num }).GetValue();
			}
			finally
			{
				OpenShotEventHandlers.IsModRefilling = false;
			}
		}
	}
}