using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using REPOLib.Modules; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: AssemblyVersion("1.0.6.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ShopBlacklist { [BepInPlugin("ShopBlacklist", "ShopBlacklist", "1.0.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ShopBlacklistPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(StatsManager), "Awake")] public static class Patch_StatsManager_Awake { [HarmonyPostfix] private static void Postfix() { try { StatsManager instance = StatsManager.instance; if (instance == null || !(instance.itemDictionary?.Count > 0)) { return; } int count = itemRefs.Count; ScanAndRegister(); if (itemRefs.Count > count) { try { ((BaseUnityPlugin)ShopBlacklistPlugin.instance).Config.Save(); return; } catch { return; } } } catch (Exception ex) { Log.LogError((object)("ShopBlacklist StatsManager.Awake: " + ex)); } } } [HarmonyPatch(typeof(ShopManager), "ShopInitialize")] public static class Patch_ShopInitialize_Pre { [HarmonyPrefix] private static void Prefix() { try { int num = 0; foreach (KeyValuePair itemRef in itemRefs) { if (!((Object)(object)itemRef.Value == (Object)null)) { bool flag = IsBlocked(itemRef.Value); if (flag && !itemRef.Value.disabled) { itemRef.Value.disabled = true; num++; } else if (!flag && itemRef.Value.disabled) { itemRef.Value.disabled = false; } } } if (num > 0) { Log.LogInfo((object)$"ShopBlacklist: pre-disabled {num} items"); } } catch (Exception ex) { Log.LogError((object)("ShopBlacklist ShopInitialize prefix: " + ex)); } } } [HarmonyPatch(typeof(ShopManager), "GetAllItemsFromStatsManager")] public static class Patch_GetAllItemsFromStatsManager { [HarmonyPostfix] private static void Postfix(ShopManager __instance) { try { ScanAndRegister(); int num = 0; num += FilterList(__instance.potentialItems); num += FilterList(__instance.potentialItemConsumables); num += FilterList(__instance.potentialItemUpgrades); num += FilterList(__instance.potentialItemHealthPacks); FieldInfo fieldInfo = AccessTools.Field(typeof(ShopManager), "potentialSecretItems"); if (fieldInfo != null) { object value = fieldInfo.GetValue(__instance); if (value != null && value.GetType().GetProperty("Values")?.GetValue(value) is IEnumerable enumerable) { foreach (object item in enumerable) { if (item is List list) { num += FilterList(list); } } } } if (num > 0) { Log.LogInfo((object)$"ShopBlacklist: removed {num} from lists"); } } catch (Exception ex) { Log.LogError((object)("ShopBlacklist GetAllItems: " + ex)); } } } [HarmonyPatch(typeof(ShopManager), "ShopCheck")] public static class Patch_ShopCheck { [HarmonyPrefix] private static void Prefix(ShopManager __instance) { try { foreach (KeyValuePair itemRef in itemRefs) { if ((Object)(object)itemRef.Value != (Object)null) { itemRef.Value.disabled = IsBlocked(itemRef.Value); } } FilterList(__instance.potentialItems); FilterList(__instance.potentialItemConsumables); FilterList(__instance.potentialItemUpgrades); FilterList(__instance.potentialItemHealthPacks); } catch { } } } [HarmonyPatch(typeof(ItemAttributes), "Awake")] public static class Patch_ItemAttributes_Awake { [HarmonyPrefix] private static bool Prefix(ItemAttributes __instance) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) try { if (ShopManager.instance == null) { return true; } if ((Object)(object)__instance.item == (Object)null) { return true; } if (!IsBlocked(__instance.item)) { return true; } Log.LogInfo((object)("ShopBlacklist: [Awake] swapping [" + __instance.item.itemName + "]")); Item val = PickReplacement(__instance.item); if ((Object)(object)val != (Object)null) { __instance.item = val; _itemAssetNameFi2?.SetValue(__instance, "Items/Item " + val.itemName); _colorPresetFi?.SetValue(__instance, val.colorPreset); _itemTypeFi?.SetValue(__instance, val.itemType); _emojiIconFi?.SetValue(__instance, val.emojiIcon); return true; } Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } catch { return true; } } } [HarmonyPatch(typeof(ItemAttributes), "LateStart")] public static class Patch_ItemAttributes_LateStart { [HarmonyPrefix] private static bool Prefix(ItemAttributes __instance) { try { if (ShopManager.instance == null) { return true; } if ((Object)(object)__instance.item == (Object)null) { return true; } if (!IsBlocked(__instance.item)) { return true; } Item val = PickReplacement(__instance.item); if ((Object)(object)val != (Object)null) { Log.LogInfo((object)("ShopBlacklist: [LateStart] swapping [" + __instance.item.itemName + "] → [" + val.itemName + "]")); __instance.item = val; _itemAssetNameFi2?.SetValue(__instance, "Items/Item " + val.itemName); return true; } Log.LogInfo((object)("ShopBlacklist: [LateStart] no replacement, destroying [" + __instance.item.itemName + "]")); Object.Destroy((Object)(object)((Component)__instance).gameObject); return false; } catch { return true; } } } [HarmonyPatch(typeof(ShopManager), "Update")] public static class Patch_ShopManager_Update { private static readonly FieldInfo _itemAssetNameFi = AccessTools.Field(typeof(ItemAttributes), "itemAssetName"); [HarmonyPostfix] private static void Postfix() { try { DestroyBlockedInScene("Update"); } catch { } } internal static string ItemNameFromAssetName(string assetName) { if (string.IsNullOrEmpty(assetName)) { return null; } int num = assetName.LastIndexOf('/'); string text = ((num >= 0) ? assetName.Substring(num + 1) : assetName); if (text.StartsWith("Item ")) { text = text.Substring(5); } return text; } } public static ShopBlacklistPlugin instance; internal static ManualLogSource Log; private static readonly Dictionary> enabledConfigs = new Dictionary>(); private static readonly Dictionary> maxAmountConfigs = new Dictionary>(); private static readonly Dictionary itemRefs = new Dictionary(); private static readonly HashSet validSections = new HashSet { "Drones", "Orbs", "Cart", "Upgrades (Item)", "Upgrades (Player)", "Crystals", "Grenades", "Melee Weapons", "Health Packs", "Guns", "Trackers", "Mines", "Pocket Cart", "Tools", "Vehicles", "Launchers", "Other" }; private static readonly Dictionary vanillaUpgradeFieldMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Health Upgrade", "playerUpgradeHealth" }, { "Sprint Speed Upgrade", "playerUpgradeSpeed" }, { "Stamina Upgrade", "playerUpgradeStamina" }, { "Strength Upgrade", "playerUpgradeStrength" }, { "Range Upgrade", "playerUpgradeRange" }, { "Extra Jump Upgrade", "playerUpgradeExtraJump" }, { "Map Player Count Upgrade", "playerUpgradeMapPlayerCount" }, { "Launch Upgrade", "playerUpgradeLaunch" }, { "Crouch Rest Upgrade", "playerUpgradeCrouchRest" }, { "Tumble Wings Upgrade", "playerUpgradeTumbleWings" }, { "Tumble Climb Upgrade", "playerUpgradeTumbleClimb" }, { "Death Head Battery Upgrade", "playerUpgradeDeathHeadBattery" } }; private static readonly Random _rng = new Random(); private static readonly FieldInfo _itemAssetNameFi2 = AccessTools.Field(typeof(ItemAttributes), "itemAssetName"); private static readonly MethodInfo _lateStartMethod = AccessTools.Method(typeof(ItemAttributes), "LateStart", (Type[])null, (Type[])null); private static readonly FieldInfo _colorPresetFi = AccessTools.Field(typeof(ItemAttributes), "colorPreset"); private static readonly FieldInfo _itemTypeFi = AccessTools.Field(typeof(ItemAttributes), "itemType"); private static readonly FieldInfo _emojiIconFi = AccessTools.Field(typeof(ItemAttributes), "emojiIcon"); private static readonly FieldInfo _itemAssetNameFi = AccessTools.Field(typeof(ItemAttributes), "itemAssetName"); private static readonly FieldInfo _shopItemFi = AccessTools.Field(typeof(ItemAttributes), "shopItem"); private void Awake() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) instance = this; Log = ((BaseUnityPlugin)this).Logger; PurgeStaleConfigSections(); Item[] array = Resources.LoadAll("Items"); for (int i = 0; i < array.Length; i++) { RegisterItem(array[i]); } if (itemRefs.Count > 0) { try { ((BaseUnityPlugin)this).Config.Save(); } catch { } Log.LogInfo((object)$"ShopBlacklist: config built with {itemRefs.Count} vanilla items."); } else { Log.LogWarning((object)"ShopBlacklist: Resources.LoadAll found no items."); } SceneManager.sceneLoaded += delegate { try { int count = itemRefs.Count; IReadOnlyList allItems = Items.AllItems; if (allItems != null) { foreach (Item item in allItems) { if ((Object)(object)item != (Object)null) { RegisterItem(item); } } } if (itemRefs.Count > count) { try { ((BaseUnityPlugin)instance).Config.Save(); } catch { } Log.LogInfo((object)$"ShopBlacklist: +{itemRefs.Count - count} modded items on scene load. Total: {itemRefs.Count}"); } } catch { } }; new Harmony("ShopBlacklist").PatchAll(); Log.LogInfo((object)"ShopBlacklist v1.0.6 loaded."); } private static string SectionForItem(Item item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected I4, but got Unknown return (int)item.itemType switch { 0 => "Drones", 1 => "Orbs", 2 => "Cart", 3 => "Upgrades (Item)", 4 => "Upgrades (Player)", 5 => "Crystals", 6 => "Grenades", 7 => "Melee Weapons", 8 => "Health Packs", 9 => "Guns", 10 => "Trackers", 11 => "Mines", 12 => "Pocket Cart", 13 => "Tools", 14 => "Vehicles", 15 => "Launchers", _ => "Other", }; } private static bool RegisterItem(Item item) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_0095: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_00f5: Expected O, but got Unknown if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(item.itemName)) { return false; } if (itemRefs.ContainsKey(item.itemName)) { return false; } itemRefs[item.itemName] = item; string text = SectionForItem(item); enabledConfigs[item.itemName] = ((BaseUnityPlugin)instance).Config.Bind(new ConfigDefinition(text, item.itemName + " - Enabled"), true, new ConfigDescription("Allow \"" + item.itemName + "\" to appear in the shop.", (AcceptableValueBase)null, Array.Empty())); maxAmountConfigs[item.itemName] = ((BaseUnityPlugin)instance).Config.Bind(new ConfigDefinition(text, item.itemName + " - Max Amount"), 0, new ConfigDescription("Stop \"" + item.itemName + "\" spawning after this many total team purchases. 0 = no cap.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 999), Array.Empty())); return true; } internal static void ScanAndRegister() { int num = 0; if (StatsManager.instance?.itemDictionary != null) { foreach (KeyValuePair item in StatsManager.instance.itemDictionary) { if ((Object)(object)item.Value != (Object)null && RegisterItem(item.Value)) { num++; } } } try { IReadOnlyList allItems = Items.AllItems; if (allItems != null) { foreach (Item item2 in allItems) { if ((Object)(object)item2 != (Object)null && RegisterItem(item2)) { num++; } } } } catch { } if (num > 0) { try { ((BaseUnityPlugin)instance).Config.Save(); } catch { } Log.LogInfo((object)$"ShopBlacklist: +{num} new items. Total: {itemRefs.Count}"); } } internal static bool IsBlocked(Item item) { if ((Object)(object)item == (Object)null || string.IsNullOrEmpty(item.itemName)) { return false; } if (enabledConfigs.TryGetValue(item.itemName, out ConfigEntry value) && !value.Value) { return true; } if (maxAmountConfigs.TryGetValue(item.itemName, out ConfigEntry value2) && value2.Value > 0) { return GetTotalPurchases(item.itemName) >= value2.Value; } return false; } private static int GetTotalPurchases(string itemName) { try { if ((Object)(object)StatsManager.instance == (Object)null) { return 0; } if (vanillaUpgradeFieldMap.TryGetValue(itemName, out string value)) { FieldInfo fieldInfo = AccessTools.Field(typeof(StatsManager), value); if (fieldInfo != null && fieldInfo.GetValue(StatsManager.instance) is Dictionary dictionary) { int num = 0; foreach (int value2 in dictionary.Values) { num += value2; } return num; } } return StatsManager.instance.GetItemsUpgradesPurchasedTotal(itemName); } catch { return 0; } } private static Item PickReplacement(Item blocked) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected I4, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Expected I4, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Invalid comparison between Unknown and I4 List list = new List(); int num = (int)blocked.itemType; foreach (List item in new List> { ShopManager.instance?.potentialItemUpgrades, ShopManager.instance?.potentialItems, ShopManager.instance?.potentialItemConsumables, ShopManager.instance?.potentialItemHealthPacks }) { if (item == null) { continue; } foreach (Item item2 in item) { if ((Object)(object)item2 != (Object)null && !IsBlocked(item2) && (int)item2.itemType == num) { list.Add(item2); } } } if (list.Count == 0) { foreach (KeyValuePair itemRef in itemRefs) { if ((Object)(object)itemRef.Value != (Object)null && !IsBlocked(itemRef.Value) && (int)itemRef.Value.itemType == num && itemRef.Value.itemName != blocked.itemName) { list.Add(itemRef.Value); } } } if (list.Count == 0) { Log.LogInfo((object)("ShopBlacklist: no same-type replacement for [" + blocked.itemName + "] (type=" + num + ")")); return null; } Item val = list[_rng.Next(list.Count)]; Log.LogInfo((object)("ShopBlacklist: replacement → [" + val.itemName + "] (type=" + (int)val.itemType + ")")); return val; } private static void SwapItem(ItemAttributes ia, Item blocked) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Invalid comparison between Unknown and I4 Item val = PickReplacement(blocked); if ((Object)(object)val == (Object)null) { Log.LogInfo((object)("ShopBlacklist: no replacement for [" + blocked.itemName + "], destroying.")); Object.Destroy((Object)(object)((Component)ia).gameObject); return; } Log.LogInfo((object)("ShopBlacklist: swapping [" + blocked.itemName + "] → [" + val.itemName + "]")); ia.item = val; _itemAssetNameFi2?.SetValue(ia, "Items/Item " + val.itemName); _colorPresetFi?.SetValue(ia, val.colorPreset); _itemTypeFi?.SetValue(ia, val.itemType); _emojiIconFi?.SetValue(ia, val.emojiIcon); ItemUpgrade component = ((Component)ia).GetComponent(); if ((Object)(object)component != (Object)null) { component.colorPreset = val.colorPreset; component.isPlayerUpgrade = (int)val.itemType == 4; } if (!(_lateStartMethod != null)) { return; } try { if (_lateStartMethod.Invoke(ia, null) is IEnumerator enumerator) { ((MonoBehaviour)ia).StartCoroutine(enumerator); } } catch { } } private static int FilterList(List list) { if (list == null) { return 0; } int num = 0; for (int num2 = list.Count - 1; num2 >= 0; num2--) { if (IsBlocked(list[num2])) { list.RemoveAt(num2); num++; } } return num; } private static void DestroyIfBlocked(ItemAttributes ia, string context) { if (ia != null && !((Object)(object)ia.item == (Object)null) && IsBlocked(ia.item)) { Log.LogInfo((object)("ShopBlacklist: [" + context + "] destroying [" + ia.item.itemName + "]")); Object.Destroy((Object)(object)((Component)ia).gameObject); } } private void PurgeStaleConfigSections() { try { string path = Path.Combine(Paths.ConfigPath, "ShopBlacklist.cfg"); if (!File.Exists(path)) { return; } List list = new List(File.ReadAllLines(path)); List list2 = new List(); bool flag = false; foreach (string item in list) { string text = item.Trim(); if (text.StartsWith("[") && text.EndsWith("]")) { string text2 = text.Substring(1, text.Length - 2); flag = !validSections.Contains(text2); if (flag) { Log.LogInfo((object)("ShopBlacklist: removing stale section [" + text2 + "]")); continue; } } if (!flag) { list2.Add(item); } } File.WriteAllLines(path, list2); ((BaseUnityPlugin)this).Config.Reload(); } catch (Exception ex) { Log.LogWarning((object)("ShopBlacklist: purge error: " + ex.Message)); } } private static bool IsShopItem(ItemAttributes ia) { try { return _shopItemFi != null && (bool)_shopItemFi.GetValue(ia); } catch { return false; } } private static void DestroyBlockedInScene(string context) { if (ShopManager.instance == null) { return; } ItemAttributes[] array = Object.FindObjectsOfType(); foreach (ItemAttributes val in array) { if (val == null) { continue; } GameObject gameObject = ((Component)val).gameObject; if ((Object)(object)gameObject == (Object)null || !IsShopItem(val)) { continue; } string text = null; if ((Object)(object)val.item != (Object)null) { if (!IsBlocked(val.item)) { continue; } text = val.item.itemName; } else { string text2 = Patch_ShopManager_Update.ItemNameFromAssetName(_itemAssetNameFi?.GetValue(val) as string); if (string.IsNullOrEmpty(text2) || !enabledConfigs.TryGetValue(text2, out ConfigEntry value) || (value.Value && (!maxAmountConfigs.TryGetValue(text2, out ConfigEntry value2) || value2.Value <= 0 || GetTotalPurchases(text2) < value2.Value))) { continue; } text = text2; } if ((Object)(object)val.item != (Object)null) { SwapItem(val, val.item); continue; } Log.LogInfo((object)("ShopBlacklist: [" + context + "] removing [" + text + "] (item not loaded yet)")); Object.Destroy((Object)(object)gameObject); } } } }