Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShopBlacklist v1.0.0
ShopBlacklist.dll
Decompiled 5 days agousing 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<string, Item> 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<Item> 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<string, Item> 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<string, ConfigEntry<bool>> enabledConfigs = new Dictionary<string, ConfigEntry<bool>>(); private static readonly Dictionary<string, ConfigEntry<int>> maxAmountConfigs = new Dictionary<string, ConfigEntry<int>>(); private static readonly Dictionary<string, Item> itemRefs = new Dictionary<string, Item>(); private static readonly HashSet<string> validSections = new HashSet<string> { "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<string, string> vanillaUpgradeFieldMap = new Dictionary<string, string>(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<Item>("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<Item> 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<bool>(new ConfigDefinition(text, item.itemName + " - Enabled"), true, new ConfigDescription("Allow \"" + item.itemName + "\" to appear in the shop.", (AcceptableValueBase)null, Array.Empty<object>())); maxAmountConfigs[item.itemName] = ((BaseUnityPlugin)instance).Config.Bind<int>(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<int>(0, 999), Array.Empty<object>())); return true; } internal static void ScanAndRegister() { int num = 0; if (StatsManager.instance?.itemDictionary != null) { foreach (KeyValuePair<string, Item> item in StatsManager.instance.itemDictionary) { if ((Object)(object)item.Value != (Object)null && RegisterItem(item.Value)) { num++; } } } try { IReadOnlyList<Item> 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<bool> value) && !value.Value) { return true; } if (maxAmountConfigs.TryGetValue(item.itemName, out ConfigEntry<int> 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<string, int> 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<Item> list = new List<Item>(); int num = (int)blocked.itemType; foreach (List<Item> item in new List<List<Item>> { 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<string, Item> 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<ItemUpgrade>(); 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<Item> 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<string> list = new List<string>(File.ReadAllLines(path)); List<string> list2 = new List<string>(); 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<ItemAttributes>(); 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<bool> value) || (value.Value && (!maxAmountConfigs.TryGetValue(text2, out ConfigEntry<int> 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); } } } }