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.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using OpenShot.Core; using OpenShot.Events; 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.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("LimitBypassMod")] [assembly: AssemblyTitle("LimitBypassMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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.4.0")] public class LimitBypassPlugin : BaseUnityPlugin { public const string PluginGuid = "com.luckyshot.limitbypass"; public const string PluginName = "Limit Bypass Mod"; public const string PluginVersion = "1.4.0"; public static ManualLogSource Log { get; private set; } private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Plugin com.luckyshot.limitbypass is loaded!"); new GameObject("LimitBypass_StringFormatter").AddComponent(); new Harmony("com.luckyshot.limitbypass").PatchAll(); Log.LogInfo((object)"Harmony patches applied successfully."); OpenShotEventHandlers.Initialize(); } } [HarmonyPatch] public static class GameManager_HandleShotFired_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(AccessTools.TypeByName("GameManager"), "HandleShotFired", (Type[])null, (Type[])null); } private static void Prefix(object __instance, out int __state) { __state = 0; if (__instance != null) { __state = Traverse.Create(__instance).Property("TotalBulletsFired", (object[])null).GetValue(); } } private static void Postfix(object __instance, int __state) { if (__instance == null) { return; } int num = Traverse.Create(__instance).Property("TotalBulletsFired", (object[])null).GetValue() - __state; 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; } } } } [HarmonyPatch] public static class ShopManager_TryBuy_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(AccessTools.TypeByName("ShopManager"), "TryBuy", (Type[])null, (Type[])null); } private static bool Prefix(int cost, ref bool __result) { if (cost > 1000000) { __result = LimitBypassDecisionAPI.CanAffordCurrency(cost); return false; } return true; } } [HarmonyPatch] public static class Weapon_HasInfiniteAmmo_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(AccessTools.TypeByName("Weapon"), "get_HasInfiniteAmmo", (Type[])null, (Type[])null); } private static bool Prefix(ref bool __result) { __result = true; return false; } } public static class OpenShotEventHandlers { public static bool IsModRefilling; 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 (IsModRefilling || weapon == null) { return; } Traverse obj = Traverse.Create(weapon); int value = obj.Property("CurrentAmmo", (object[])null).GetValue(); int num = obj.Property("MaxAmmo", (object[])null).GetValue() - value; if (amount >= num && num > 0) { foreach (KeyValuePair 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 ammoPool2 in ShadowState.AmmoPools) { if (ammoPool2.Key != "Normal") { ShadowState.CurrentAmmo[ammoPool2.Key] = ammoPool2.Value; } } } ShadowState.IsAmmoDirty = true; } private static void OnMoneyAmountChanged(object view) { TMP_Text value = Traverse.Create(view).Field("_text").GetValue(); if ((Object)(object)value != (Object)null && ShadowState.Currency > 2000000000L) { value.text = StringFormatter.Instance.CachedCurrencyString; } } private static void OnTicketAmountChanged(object view) { TMP_Text value = Traverse.Create(view).Field("_text").GetValue(); if ((Object)(object)value != (Object)null && ShadowState.TotalTargetsDestroyed > 2000000000L) { value.text = StringFormatter.Instance.CachedTargetsString; } } private static void OnAmmoDisplayUpdated(object view) { TMP_Text value = Traverse.Create(view).Field("bulletCountText").GetValue(); if (!((Object)(object)value != (Object)null)) { return; } List value2 = Traverse.Create(view).Field("_renderedMagazine").GetValue>(); if (value2 != null && value2.Count > 0) { string value3 = Traverse.Create(value2[0]).Property("name", (object[])null).GetValue(); if (value3 != null && ShadowState.CurrentAmmo.ContainsKey(value3) && ShadowState.CurrentAmmo[value3] > 2000000000L) { value.text = StringFormatter.Instance.GetAmmoString(value3); } } else if (ShadowState.CurrentAmmo.ContainsKey("Normal") && ShadowState.CurrentAmmo["Normal"] > 2000000000L) { 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 AmmoPools { get; } = new Dictionary(); public static Dictionary CurrentAmmo { get; } = new Dictionary(); 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 CachedAmmoStrings { get; } = new Dictionary(); 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 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 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 ((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 (__instance == null) { return; } Traverse val = Traverse.Create(__instance); int value = val.Property("CurrentAmmo", (object[])null).GetValue(); int value2 = val.Property("MaxAmmo", (object[])null).GetValue(); if (value >= value2) { return; } bool flag = false; foreach (BigInteger value3 in ShadowState.CurrentAmmo.Values) { if (value3 > 0L) { flag = true; break; } } if (flag) { int num = value2 - value; OpenShotEventHandlers.IsModRefilling = true; try { val.Method("AddNormalBulletsToMagazine", new object[1] { num }).GetValue(); } finally { OpenShotEventHandlers.IsModRefilling = false; } } } } }