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 All Shop Items In Level v1.0.0
plugins/REPO_All_Shop_Items_in_Level.dll
Decompiled 2 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; 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 Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 REPO_All_Shop_Items_in_Level { public class UsedVolumeTracker : MonoBehaviour { } public class SpawnedItemTracker : MonoBehaviour { } [BepInPlugin("REPO_All_Shop_Items_in_Level", "ALL Shop Items spawn in Level", "1.7.21")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(EnemyParent), "Despawn")] private class DespawnPatch { private static int GetSpawnValuableCurrent(EnemyParent ep) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown Enemy val = (Enemy)(AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(ep)); if ((Object)(object)val == (Object)null) { return 0; } EnemyHealth val2 = (EnemyHealth)(AccessTools.Field(typeof(Enemy), "Health")?.GetValue(val)); if ((Object)(object)val2 == (Object)null) { return 0; } FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyHealth), "spawnValuableCurrent"); if (fieldInfo == null) { return 0; } return (int)fieldInfo.GetValue(val2); } private static void Prefix(EnemyParent __instance, out int __state) { __state = GetSpawnValuableCurrent(__instance); } private static void Postfix(EnemyParent __instance, int __state) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer() && SpawnHealthPacksFromEnemies.Value && GetSpawnValuableCurrent(__instance) > __state) { Item item; if (Random.Range(0f, 100f) > HealthPackDropChance.Value) { Logger.LogInfo((object)$"Health pack roll failed (chance: {HealthPackDropChance.Value}%)"); } else if (GetRandomItemOfType((itemType)8, out item)) { Enemy val = (Enemy)(AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(__instance)); Transform val2 = (Object.op_Implicit((Object)(object)val.CustomValuableSpawnTransform) ? val.CustomValuableSpawnTransform : val.CenterTransform); SpawnItem(item, val2.position + new Vector3(0f, 1f, 0f), Quaternion.identity); } } } } [HarmonyPatch] private class ValuableDirector_Spawn_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ValuableDirector), "Spawn", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(ValuableDirector), "SpawnValuable", (Type[])null, (Type[])null); } [HarmonyPrefix] private static void Prefix(object[] __args) { ValuableVolume val = __args.OfType<ValuableVolume>().FirstOrDefault(); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.AddComponent<UsedVolumeTracker>(); } } } internal static ManualLogSource Logger; internal static ConfigEntry<bool> SpawnUpgradeItems; internal static ConfigEntry<float> UpgradeItemSpawnChance; internal static ConfigEntry<bool> MapHideUpgradeItems; internal static ConfigEntry<bool> UseShopPriceForUpgradeItems; internal static ConfigEntry<bool> SpawnDroneItems; internal static ConfigEntry<float> DroneItemSpawnChance; internal static ConfigEntry<bool> MapHideDroneItems; internal static ConfigEntry<bool> UseShopPriceForDroneItems; internal static ConfigEntry<bool> SpawnOtherShopItems; internal static ConfigEntry<float> OtherShopItemSpawnChance; internal static ConfigEntry<bool> MapHideOtherShopItems; internal static ConfigEntry<bool> UseShopPriceForOtherItems; internal static ConfigEntry<bool> SpawnHealthPacksFromEnemies; internal static ConfigEntry<float> HealthPackDropChance; internal static ConfigEntry<float> MinItemValue; internal static ConfigEntry<float> MaxItemValue; internal static ConfigEntry<int> MaxItemsPerLevel; internal static Dictionary<string, ConfigEntry<bool>> ItemAllowList; private static readonly HashSet<int> KnownSpecialTypes = new HashSet<int> { 0, 3, 8 }; public static Plugin Instance { get; private set; } private void Awake() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected O, but got Unknown //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Expected O, but got Unknown //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Expected O, but got Unknown //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Plugin REPO_All_Shop_Items_in_Level is loaded!"); Harmony val = new Harmony("REPO_All_Shop_Items_in_Level"); val.PatchAll(typeof(Plugin)); val.PatchAll(typeof(DespawnPatch)); val.PatchAll(typeof(ValuableDirector_Spawn_Patch)); Logger.LogInfo((object)"Harmony patches applied!"); SpawnUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "SpawnUpgradeItems", true, "Whether upgrade items can spawn in levels"); MapHideUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "MapHideUpgradeItems", true, "(Client) Whether upgrade items are hidden on the map"); UpgradeItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("1_UpgradeItems", "UpgradeItemSpawnChance", 2.5f, new ConfigDescription("% chance for an upgrade item to spawn per eligible volume", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "UseShopPriceForItemSelection", true, "If ON: Cheaper upgrade items appear more often. If OFF: Equal chance."); SpawnDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "SpawnDroneItems", true, "Whether drone items can spawn in levels"); MapHideDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "MapHideDroneItems", true, "(Client) Whether drone items are hidden on the map"); DroneItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("2_DroneItems", "DroneItemsSpawnChance", 0.95f, new ConfigDescription("% chance for a drone item to spawn per eligible volume", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "UseShopPriceForItemSelection", true, "If ON: Cheaper drone items appear more often. If OFF: Equal chance."); SpawnOtherShopItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "SpawnOtherShopItems", true, "Whether weapons/consumables/misc shop items can spawn in levels"); MapHideOtherShopItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "MapHideOtherShopItems", false, "(Client) Whether other shop items are hidden on the map"); OtherShopItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("3_OtherShopItems", "OtherShopItemSpawnChance", 1.5f, new ConfigDescription("% chance for a weapon/consumable/misc item to spawn per eligible volume", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForOtherItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "UseShopPriceForItemSelection", true, "If ON: Cheaper items appear more often. If OFF: Equal chance."); SpawnHealthPacksFromEnemies = ((BaseUnityPlugin)this).Config.Bind<bool>("4_HealthPacks", "SpawnHealthPacksFromEnemies", true, "Whether health packs can spawn when enemies die"); HealthPackDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("4_HealthPacks", "HealthPackDropChance", 100f, new ConfigDescription("% chance for a health pack to drop on enemy death", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); MinItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MinItemValue", 0f, new ConfigDescription("Don't spawn items with a shop value below this. 0 = no minimum.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MaxItemValue", 0f, new ConfigDescription("Don't spawn items with a shop value above this. 0 = no maximum.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("5_Filters", "MaxItemsPerLevel", 0, new ConfigDescription("Hard cap on total items spawned per level. 0 = unlimited.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); } [HarmonyPatch(typeof(MainMenuOpen), "Awake")] [HarmonyPostfix] public static void MainMenuOpen_Awake_Postfix() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected I4, but got Unknown if (ItemAllowList != null) { return; } Logger.LogInfo((object)"Initializing per-item allow list"); ItemAllowList = new Dictionary<string, ConfigEntry<bool>>(); foreach (Item value2 in StatsManager.instance.itemDictionary.Values) { int num = (int)value2.itemType; string text; if (num == 0) { text = "6_AllowedItems_Drones"; } else if (num == 3) { text = "6_AllowedItems_Upgrades"; } else { if (num == 8) { continue; } text = "6_AllowedItems_OtherShop"; } string name = ((Object)value2).name; ConfigEntry<bool> value = ((BaseUnityPlugin)Instance).Config.Bind<bool>(text, name, true, "Allow '" + name + "' to spawn in levels"); ItemAllowList[name] = value; } Logger.LogInfo((object)$"Registered {ItemAllowList.Count} items in allow list"); } private static bool PassesValueFilter(Item item) { float num = (((Object)(object)item.value != (Object)null) ? item.value.valueMin : 0f); if (MinItemValue.Value > 0f && num < MinItemValue.Value) { return false; } if (MaxItemValue.Value > 0f && num > MaxItemValue.Value) { return false; } return true; } private static bool IsItemAllowed(Item item) { string name = ((Object)item).name; if (ItemAllowList == null) { return true; } if (ItemAllowList.TryGetValue(name, out var value)) { return value.Value; } return true; } private static List<Item> GetCandidates(Func<Item, bool> typeFilter) { return (from i in StatsManager.instance.itemDictionary.Values.Where(typeFilter) where (Object)(object)i.value != (Object)null && i.value.valueMin > 0f select i).Where(PassesValueFilter).Where(IsItemAllowed).ToList(); } private static Item WeightedOrRandom(List<Item> list, bool usePrice) { if (!usePrice) { return list[Random.Range(0, list.Count)]; } float num = list.Sum((Item i) => 1f / i.value.valueMin); if (num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { return null; } float num2 = Random.Range(0f, num); foreach (Item item in list) { num2 -= 1f / item.value.valueMin; if (num2 <= 0f) { return item; } } return null; } private static bool GetRandomItemOfType(itemType type, out Item item) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) item = null; List<Item> candidates = GetCandidates((Item i) => i.itemType == type); if (candidates.Count == 0) { Logger.LogWarning((object)$"No valid items for type {type}."); return false; } item = candidates[Random.Range(0, candidates.Count)]; return true; } private static bool GetRandomOtherShopItem(out Item item) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) item = null; List<Item> candidates = GetCandidates((Item i) => !KnownSpecialTypes.Contains((int)i.itemType)); if (candidates.Count == 0) { Logger.LogWarning((object)"No valid other-shop items found."); return false; } item = WeightedOrRandom(candidates, UseShopPriceForOtherItems.Value); if ((Object)(object)item == (Object)null) { Logger.LogWarning((object)"Weighted selection failed for other-shop items."); return false; } Logger.LogInfo((object)$"Other shop item selected: {((Object)item).name} (type {item.itemType}, value {item.value.valueMin})"); return true; } private static bool HasValuablePropSwitch(ValuableVolume volume) { return (Object)(object)((Component)volume).GetComponentInParent<ValuablePropSwitch>() != (Object)null; } private static bool ShouldSpawnItem(ValuableVolume volume, out string category) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected I4, but got Unknown category = null; if (HasValuablePropSwitch(volume)) { return false; } switch ((int)volume.VolumeType) { case 0: if (!SpawnUpgradeItems.Value) { return false; } category = "upgrade"; return Random.Range(0f, 100f) <= UpgradeItemSpawnChance.Value; case 1: if (!SpawnDroneItems.Value) { return false; } category = "drone"; return Random.Range(0f, 100f) <= DroneItemSpawnChance.Value; default: if (!SpawnOtherShopItems.Value) { return false; } category = "other"; return Random.Range(0f, 100f) <= OtherShopItemSpawnChance.Value; } } private static GameObject SpawnItem(Item item, Vector3 position, Quaternion rotation) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (SemiFunc.IsMultiplayer() ? PhotonNetwork.Instantiate("Items/" + ((Object)item).name, position, rotation, (byte)0, (object[])null) : Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)item.prefab).Prefab, position, rotation)); val.AddComponent<SpawnedItemTracker>(); return val; } private static bool RandomItemSpawn(ValuableVolume volume) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!ShouldSpawnItem(volume, out var category)) { return false; } if (!((category == "upgrade") ? GetRandomItemOfType((itemType)3, out var item) : ((!(category == "drone")) ? GetRandomOtherShopItem(out item) : GetRandomItemOfType((itemType)0, out item)))) { return false; } SpawnItem(item, ((Component)volume).transform.position, ((Component)volume).transform.rotation); return true; } [HarmonyPatch(typeof(ValuableDirector), "VolumesAndSwitchSetup")] [HarmonyPostfix] public static void ValuableDirector_VolumesAndSwitchSetup_Postfix(ValuableDirector __instance) { if (!SemiFunc.RunIsLevel()) { return; } List<ValuableVolume> list = (from v in Object.FindObjectsOfType<ValuableVolume>(false) where (Object)(object)((Component)v).gameObject.GetComponent<UsedVolumeTracker>() == (Object)null where !HasValuablePropSwitch(v) select v).ToList(); Logger.LogInfo((object)$"Found {list.Count} potential volumes"); Logger.LogInfo((object)$" tiny (upgrade): {list.Count((ValuableVolume v) => (int)v.VolumeType == 0)} @ {UpgradeItemSpawnChance.Value}%"); Logger.LogInfo((object)$" small (drone): {list.Count((ValuableVolume v) => (int)v.VolumeType == 1)} @ {DroneItemSpawnChance.Value}%"); Logger.LogInfo((object)$" other (shop): {list.Count((ValuableVolume v) => (int)v.VolumeType >= 2)} @ {OtherShopItemSpawnChance.Value}%"); int value = MaxItemsPerLevel.Value; int num = 0; foreach (ValuableVolume item in list) { if (value > 0 && num >= value) { Logger.LogInfo((object)$"Hit MaxItemsPerLevel cap ({value}), stopping"); break; } if (RandomItemSpawn(item)) { num++; } } Logger.LogInfo((object)($"Spawned {num} items total" + ((value > 0) ? $" (cap: {value})" : ""))); } [HarmonyPatch(typeof(Map), "AddCustom")] [HarmonyPostfix] public static void Map_AddCustom_Postfix(MapCustom mapCustom) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected I4, but got Unknown if (!SemiFunc.RunIsLevel()) { return; } ItemAttributes val = null; if (((Component)mapCustom).gameObject.TryGetComponent<ItemAttributes>(ref val)) { int num = (int)val.item.itemType; if ((num == 3 && MapHideUpgradeItems.Value) || (num == 0 && MapHideDroneItems.Value) || (!KnownSpecialTypes.Contains(num) && MapHideOtherShopItems.Value)) { ((Component)mapCustom).gameObject.SetActive(false); } } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInHaulList")] [HarmonyPostfix] public static void ExtractionPoint_DestroyAllPhysObjectsInHaulList_Postfix(ExtractionPoint __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } List<GameObject> list = (from t in Object.FindObjectsOfType<SpawnedItemTracker>(false) select ((Component)t).gameObject).ToList(); foreach (GameObject item in list) { RoomVolumeCheck component = item.GetComponent<RoomVolumeCheck>(); if (!((Object)(object)component == (Object)null) && component.CurrentRooms.Any((RoomVolume r) => r.Extraction)) { ItemAttributes component2 = item.GetComponent<ItemAttributes>(); Logger.LogInfo((object)("Adding extracted item " + ((Object)component2.item).name + " to purchased items")); StatsManager.instance.ItemPurchase(((Object)component2.item).name); item.GetComponent<PhysGrabObject>().DestroyPhysGrabObject(); } } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "REPO_All_Shop_Items_in_Level"; public const string PLUGIN_NAME = "ALL Shop Items spawn in Level"; public const string PLUGIN_VERSION = "1.7.21"; } }