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.8.0
plugins/REPO_All_Shop_Items_in_Level.dll
Decompiled a month agousing System; using System.Collections; 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] [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 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.8.0")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(EnemyParent), "Despawn")] private class DespawnPatch { private static int GetSpawnValuableCurrent(EnemyParent ep) { try { object? obj = AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(ep); Enemy obj2 = (Enemy)((obj is Enemy) ? obj : null); object? obj3 = AccessTools.Field(typeof(Enemy), "Health")?.GetValue(obj2); EnemyHealth obj4 = (EnemyHealth)((obj3 is EnemyHealth) ? obj3 : null); FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyHealth), "spawnValuableCurrent"); return (!(fieldInfo == null)) ? ((int)fieldInfo.GetValue(obj4)) : 0; } catch (Exception ex) { DebugLog("Error reading spawnValuableCurrent: " + ex.Message); return 0; } } private static itemType GetLootTypeForEnemy(EnemyParent ep) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (!EnableEnemyLootTables.Value) { return (itemType)8; } string text = ((Object)ep).name?.ToLower() ?? ""; if (text.Contains("gnome") || text.Contains("small")) { return (itemType)3; } if (text.Contains("large") || text.Contains("boss")) { return (itemType)0; } return (itemType)8; } private static void Prefix(EnemyParent __instance, out int __state) { __state = GetSpawnValuableCurrent(__instance); } private static void Postfix(EnemyParent __instance, int __state) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || !SpawnHealthPacksFromEnemies.Value || GetSpawnValuableCurrent(__instance) <= __state || Random.Range(0f, 100f) > HealthPackDropChance.Value) { return; } itemType lootTypeForEnemy = GetLootTypeForEnemy(__instance); if ((!GetRandomItemOfType(lootTypeForEnemy, out var item) && !GetRandomItemOfType((itemType)8, out item)) || (Object)(object)item == (Object)null) { return; } try { object? obj = AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(__instance); Enemy val = (Enemy)((obj is Enemy) ? obj : null); if ((Object)(object)val == (Object)null) { return; } Transform val2 = (Object.op_Implicit((Object)(object)val.CustomValuableSpawnTransform) ? val.CustomValuableSpawnTransform : val.CenterTransform); if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = val2.position + Vector3.up; if (!IsPositionValid(val3)) { DebugLog("Enemy " + ((Object)__instance).name + " has invalid spawn position, skipping drop"); return; } SpawnItem(item, val3, Quaternion.identity); DebugLog($"Dropped {((Object)item).name} from {((Object)__instance).name} ({lootTypeForEnemy})"); } } catch (Exception ex) { DebugLog("Error spawning enemy loot: " + ex.Message); } } } [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> DebugMode; internal static ConfigEntry<bool> SaveAllOnLevelComplete; 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 ConfigEntry<int> MinItemsPerLevel; internal static ConfigEntry<bool> EnableLevelScaling; internal static ConfigEntry<float> LevelScalingMultiplier; internal static ConfigEntry<bool> AnnounceRareItems; internal static ConfigEntry<float> AnnounceValueThreshold; internal static ConfigEntry<bool> EnableEnemyLootTables; internal static List<ConfigEntry<bool>> DisallowedUpgradeItems; internal static List<ConfigEntry<bool>> DisallowedDroneItems; internal static List<ConfigEntry<bool>> DisallowedOtherItems; private static readonly HashSet<int> KnownSpecialTypes = new HashSet<int> { 0, 3, 8 }; private static Dictionary<string, Item> _cachedItemDictionary; private static List<Item> _cachedUpgrades; private static List<Item> _cachedDrones; private static List<Item> _cachedOtherItems; private static float _lastItemRefreshTime; private static bool _isSpawning = false; public static Plugin Instance { get; private set; } internal static void DebugLog(string message) { if (DebugMode != null && DebugMode.Value) { Logger.LogInfo((object)("[DEBUG] " + message)); } } 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Expected O, but got Unknown //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Expected O, but got Unknown //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Expected O, but got Unknown //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Expected O, but got Unknown //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Expected O, but got Unknown //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Expected O, but got Unknown //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Expected O, but got Unknown //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_047e: 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!"); DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("0_Debug", "DebugMode", false, "Enable verbose debug logging."); SaveAllOnLevelComplete = ((BaseUnityPlugin)this).Config.Bind<bool>("0_Debug", "SaveAllOnLevelComplete", true, "If true, all spawned items still in the level are saved when you complete a level."); 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", "MapHideShopUpgradeItems", false, "(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", (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."); 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", false, "(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", (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."); SpawnOtherShopItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "SpawnOtherShopItems", true, "Whether other 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 other shop items to spawn", (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."); 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 when an enemy dies", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); MinItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MinItemValue", 0f, new ConfigDescription("Minimum item value for spawning (0 = disabled)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MaxItemValue", 0f, new ConfigDescription("Maximum item value for spawning (0 = disabled)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("5_Filters", "MaxItemsPerLevel", 0, new ConfigDescription("Maximum items to spawn per level (0 = unlimited)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); MinItemsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("5_Filters", "MinItemsPerLevel", 0, new ConfigDescription("Minimum items guaranteed to spawn per level (0 = disabled)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); EnableLevelScaling = ((BaseUnityPlugin)this).Config.Bind<bool>("6_LevelScaling", "EnableLevelScaling", true, "Spawn chances scale up as you progress through floors"); LevelScalingMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("6_LevelScaling", "LevelScalingMultiplier", 0.1f, new ConfigDescription("Bonus multiplier per floor completed (0.1 = +10% per floor)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); AnnounceRareItems = ((BaseUnityPlugin)this).Config.Bind<bool>("7_Announce", "AnnounceRareItems", true, "Log to console when an expensive item spawns"); AnnounceValueThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("7_Announce", "AnnounceValueThreshold", 5000f, new ConfigDescription("Min item value to trigger announce", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); EnableEnemyLootTables = ((BaseUnityPlugin)this).Config.Bind<bool>("8_EnemyLoot", "EnableEnemyLootTables", true, "Specific enemy types drop specific item types instead of always health packs"); DisallowedUpgradeItems = new List<ConfigEntry<bool>>(); DisallowedDroneItems = new List<ConfigEntry<bool>>(); DisallowedOtherItems = new List<ConfigEntry<bool>>(); ((MonoBehaviour)this).StartCoroutine(InitializeItemListsWhenReady()); } private IEnumerator InitializeItemListsWhenReady() { float startTime = Time.time; float timeout = 30f; while ((Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null || StatsManager.instance.itemDictionary.Count == 0) { if (Time.time - startTime > timeout) { Logger.LogError((object)"StatsManager failed to initialize within timeout - item filtering disabled"); yield break; } yield return null; } Logger.LogInfo((object)"Initializing per-item disable lists"); _cachedItemDictionary = StatsManager.instance.itemDictionary; foreach (Item item in _cachedItemDictionary.Values) { string itemName = ((Object)item).name; itemType itemType = item.itemType; itemType val = itemType; itemType val2 = val; if ((int)val2 != 0) { if ((int)val2 == 3) { ConfigEntry<bool> upgradeEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("9_DisallowedItems_Upgrades", itemName, false, new ConfigDescription("Disable '" + itemName + "' from spawning in levels", (AcceptableValueBase)null, Array.Empty<object>())); if (upgradeEntry.Value) { DisallowedUpgradeItems.Add(upgradeEntry); } } else if (!KnownSpecialTypes.Contains((int)item.itemType) && (Object)(object)item.value != (Object)null && item.value.valueMin > 0f) { ConfigEntry<bool> otherEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("9_DisallowedItems_OtherShop", itemName, false, new ConfigDescription("Disable '" + itemName + "' from spawning in levels", (AcceptableValueBase)null, Array.Empty<object>())); if (otherEntry.Value) { DisallowedOtherItems.Add(otherEntry); } } } else { ConfigEntry<bool> droneEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("9_DisallowedItems_Drones", itemName, false, new ConfigDescription("Disable '" + itemName + "' from spawning in levels", (AcceptableValueBase)null, Array.Empty<object>())); if (droneEntry.Value) { DisallowedDroneItems.Add(droneEntry); } } } Logger.LogInfo((object)$"Initialized disallows: Upgrades={DisallowedUpgradeItems.Count} Drones={DisallowedDroneItems.Count} Other={DisallowedOtherItems.Count}"); RefreshCachedItemLists(); } private static void RefreshCachedItemLists() { if (StatsManager.instance?.itemDictionary != null) { _cachedItemDictionary = StatsManager.instance.itemDictionary; _cachedUpgrades = GetCandidates((Item i) => (int)i.itemType == 3); _cachedDrones = GetCandidates((Item i) => (int)i.itemType == 0); _cachedOtherItems = GetCandidates((Item i) => !KnownSpecialTypes.Contains((int)i.itemType)); _lastItemRefreshTime = Time.time; DebugLog($"Cache refreshed: {_cachedUpgrades.Count} upgrades, {_cachedDrones.Count} drones, {_cachedOtherItems.Count} other"); } } 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, List<ConfigEntry<bool>> disallowedList) { string key = ((Object)item).name; return !disallowedList.Any((ConfigEntry<bool> entry) => ((ConfigEntryBase)entry).Definition.Key == key && entry.Value); } private static List<Item> GetCandidates(Func<Item, bool> typeFilter) { if (StatsManager.instance?.itemDictionary == null) { return new List<Item>(); } 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).ToList(); } private static Item WeightedOrRandom(List<Item> list, bool usePrice) { if (list == null || list.Count == 0) { return null; } if (!usePrice) { return list[Random.Range(0, list.Count)]; } float num = list.Sum((Item i) => 1f / Mathf.Max(0.01f, i.value.valueMin)); if (num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { return list[Random.Range(0, list.Count)]; } int num2 = 0; while (num2++ < 50) { float num3 = Random.Range(0f, num); foreach (Item item in list) { num3 -= 1f / Mathf.Max(0.01f, item.value.valueMin); if (num3 <= 0f) { return item; } } } return list[0]; } private static float GetScaledChance(float baseChance) { if (!EnableLevelScaling.Value) { return baseChance; } if ((Object)(object)RunManager.instance == (Object)null) { return baseChance; } int levelsCompleted = RunManager.instance.levelsCompleted; return Mathf.Min(baseChance * (1f + (float)levelsCompleted * LevelScalingMultiplier.Value), 100f); } private static bool IsPositionValid(Vector3 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (float.IsNaN(pos.x) || float.IsNaN(pos.y) || float.IsNaN(pos.z)) { return false; } if (pos == Vector3.zero) { return false; } return true; } private static bool IsVolumeStillValid(ValuableVolume volume) { if ((Object)(object)volume == (Object)null) { return false; } if ((Object)(object)volume == (Object)null || (Object)(object)((Component)volume).gameObject == (Object)null) { return false; } if (!((Component)volume).gameObject.activeInHierarchy) { return false; } return true; } private static void AnnounceItem(Item item, Vector3 position) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (AnnounceRareItems.Value && !((Object)(object)item?.value == (Object)null) && !(item.value.valueMin < AnnounceValueThreshold.Value)) { Logger.LogInfo((object)$"[RARE SPAWN] {((Object)item).name} (value ~{item.value.valueMin}) at {position}"); } } private static bool GetRandomItemOfType(itemType type, out Item item, bool usePriceWeighting = true) { //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) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between Unknown and I4 item = null; List<Item> list = null; List<ConfigEntry<bool>> disallowedList = null; if ((int)type != 0) { if ((int)type != 3) { if ((int)type == 8) { list = GetCandidates((Item i) => (int)i.itemType == 8); disallowedList = null; usePriceWeighting = true; } else { list = _cachedOtherItems; disallowedList = DisallowedOtherItems; usePriceWeighting = UseShopPriceForOtherItems.Value; } } else { list = _cachedUpgrades; disallowedList = DisallowedUpgradeItems; usePriceWeighting = UseShopPriceForUpgradeItems.Value; } } else { list = _cachedDrones; disallowedList = DisallowedDroneItems; usePriceWeighting = UseShopPriceForDroneItems.Value; } if (list == null || list.Count == 0) { return false; } if (disallowedList != null && disallowedList.Count > 0) { list = list.Where((Item i) => IsItemAllowed(i, disallowedList)).ToList(); if (list.Count == 0) { return false; } } if (Time.time - _lastItemRefreshTime > 60f) { RefreshCachedItemLists(); } item = WeightedOrRandom(list, usePriceWeighting); return (Object)(object)item != (Object)null; } private static GameObject SpawnItem(Item item, Vector3 position, Quaternion rotation) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || item.prefab == null) { DebugLog("Spawn failed: null item or prefab"); return null; } if (!IsPositionValid(position)) { DebugLog($"Spawn of {((Object)item).name} rejected: bad position {position}"); return null; } if (_isSpawning) { DebugLog("Spawn of " + ((Object)item).name + " blocked: already inside a spawn call"); return null; } _isSpawning = true; try { string text = "Items/" + ((Object)item).name; GameObject val; if (SemiFunc.IsMultiplayer()) { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { DebugLog("Spawn of " + ((Object)item).name + " blocked: not in a Photon room"); return null; } val = PhotonNetwork.InstantiateRoomObject(text, position, rotation, (byte)0, (object[])null); } else { val = Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)item.prefab).Prefab, position, rotation); } if ((Object)(object)val != (Object)null) { val.AddComponent<SpawnedItemTracker>(); AnnounceItem(item, position); DebugLog($"Spawned {((Object)item).name} at {position}"); } return val; } catch (Exception ex) { DebugLog("Spawn of " + ((Object)item).name + " threw: " + ex.Message); return null; } finally { _isSpawning = false; } } 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) <= GetScaledChance(UpgradeItemSpawnChance.Value); case 1: if (!SpawnDroneItems.Value) { return false; } category = "drone"; return Random.Range(0f, 100f) <= GetScaledChance(DroneItemSpawnChance.Value); default: if (!SpawnOtherShopItems.Value) { return false; } category = "other"; return Random.Range(0f, 100f) <= GetScaledChance(OtherShopItemSpawnChance.Value); } } private static bool RandomItemSpawn(ValuableVolume volume) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) if (!IsVolumeStillValid(volume)) { return false; } if (!ShouldSpawnItem(volume, out var category)) { return false; } Item item; bool flag = ((category == "upgrade") ? GetRandomItemOfType((itemType)3, out item) : ((!(category == "drone")) ? GetRandomItemOfType((itemType)999, out item) : GetRandomItemOfType((itemType)0, out item))); if (!flag || (Object)(object)item == (Object)null) { return false; } return (Object)(object)SpawnItem(item, ((Component)volume).transform.position, ((Component)volume).transform.rotation) != (Object)null; } [HarmonyPatch(typeof(ValuableDirector), "VolumesAndSwitchSetup")] [HarmonyPostfix] public static void ValuableDirector_VolumesAndSwitchSetup_Postfix() { //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.RunIsLevel() || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } RefreshCachedItemLists(); 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} volumes | upgrade:{GetScaledChance(UpgradeItemSpawnChance.Value):F1}% drone:{GetScaledChance(DroneItemSpawnChance.Value):F1}% other:{GetScaledChance(OtherShopItemSpawnChance.Value):F1}%"); Logger.LogInfo((object)$"Item pool: {_cachedUpgrades?.Count ?? 0} upgrades | {_cachedDrones?.Count ?? 0} drones | {_cachedOtherItems?.Count ?? 0} other"); int value = MaxItemsPerLevel.Value; int value2 = MinItemsPerLevel.Value; int num = 0; foreach (ValuableVolume item2 in list) { if (value > 0 && num >= value) { break; } if (RandomItemSpawn(item2)) { num++; } } if (value2 > 0 && num < value2) { List<ValuableVolume> list2 = list.Where((ValuableVolume v) => (Object)(object)((Component)v).gameObject.GetComponent<UsedVolumeTracker>() == (Object)null).ToList(); for (int num2 = list2.Count - 1; num2 > 0; num2--) { int num3 = Random.Range(0, num2 + 1); List<ValuableVolume> list3 = list2; int index = num2; int index2 = num3; ValuableVolume value3 = list2[num3]; ValuableVolume value4 = list2[num2]; list3[index] = value3; list2[index2] = value4; } foreach (ValuableVolume item3 in list2) { if (num >= value2 || (value > 0 && num >= value)) { break; } if (IsVolumeStillValid(item3) && (GetRandomItemOfType((itemType)3, out var item) || GetRandomItemOfType((itemType)0, out item) || GetRandomItemOfType((itemType)999, out item)) && !((Object)(object)item == (Object)null)) { Component val = (Component)(object)item3; if ((Object)(object)SpawnItem(item, val.transform.position, val.transform.rotation) != (Object)null) { num++; } } } } Logger.LogInfo((object)$"Spawned {num} items (min={value2} cap={value})"); } [HarmonyPatch(typeof(Map), "AddCustom")] [HarmonyPostfix] public static void Map_AddCustom_Postfix(MapCustom mapCustom) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected I4, but got Unknown ItemAttributes val = default(ItemAttributes); if (SemiFunc.RunIsLevel() && !((Object)(object)mapCustom == (Object)null) && !((Object)(object)((Component)mapCustom).gameObject == (Object)null) && ((Component)mapCustom).gameObject.TryGetComponent<ItemAttributes>(ref val) && !((Object)(object)val?.item == (Object)null)) { 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); DebugLog("Hidden " + ((Object)val.item).name + " from map"); } } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInHaulList")] [HarmonyPostfix] public static void ExtractionPoint_DestroyAllPhysObjectsInHaulList_Postfix(ExtractionPoint __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } SpawnedItemTracker[] array = Object.FindObjectsOfType<SpawnedItemTracker>(false); if (array.Length == 0) { return; } HashSet<string> hashSet = new HashSet<string>(); int num = 0; SpawnedItemTracker[] array2 = array; foreach (SpawnedItemTracker spawnedItemTracker in array2) { GameObject gameObject = ((Component)spawnedItemTracker).gameObject; if ((Object)(object)gameObject == (Object)null) { continue; } bool flag = false; RoomVolumeCheck component = gameObject.GetComponent<RoomVolumeCheck>(); if (component?.CurrentRooms != null && component.CurrentRooms.Any((RoomVolume r) => (Object)(object)r != (Object)null && r.Extraction)) { flag = true; } PhysGrabObject component2 = gameObject.GetComponent<PhysGrabObject>(); if ((Object)(object)component2 != (Object)null && component2.grabbed) { flag = true; } if (!flag) { continue; } ItemAttributes component3 = gameObject.GetComponent<ItemAttributes>(); if ((Object)(object)component3?.item == (Object)null) { continue; } string name = ((Object)component3.item).name; if (hashSet.Contains(name)) { continue; } if ((Object)(object)StatsManager.instance == (Object)null) { DebugLog("StatsManager is null during extraction, skipping " + name); continue; } Logger.LogInfo((object)("Saving extracted item: " + name)); StatsManager.instance.ItemPurchase(name); hashSet.Add(name); if ((Object)(object)component2 != (Object)null) { component2.DestroyPhysGrabObject(); } num++; } Logger.LogInfo((object)$"Saved {num} unique items from extraction"); } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] [HarmonyPrefix] public static void RunManager_ChangeLevel_Prefix(RunManager __instance, bool _completedLevel, bool _levelFailed, int _changeLevelType) { if (!SemiFunc.IsMasterClientOrSingleplayer() || !_completedLevel || _levelFailed || !SaveAllOnLevelComplete.Value || _changeLevelType == 4) { return; } SpawnedItemTracker[] array = Object.FindObjectsOfType<SpawnedItemTracker>(false); if (array.Length == 0) { return; } Logger.LogInfo((object)$"Level complete. Fallback-saving {array.Length} spawned items..."); HashSet<string> hashSet = new HashSet<string>(); int num = 0; SpawnedItemTracker[] array2 = array; foreach (SpawnedItemTracker spawnedItemTracker in array2) { GameObject gameObject = ((Component)spawnedItemTracker).gameObject; if ((Object)(object)gameObject == (Object)null) { continue; } ItemAttributes component = gameObject.GetComponent<ItemAttributes>(); if ((Object)(object)component?.item == (Object)null) { continue; } string name = ((Object)component.item).name; if (!hashSet.Contains(name)) { PhysGrabObject component2 = gameObject.GetComponent<PhysGrabObject>(); if ((Object)(object)component2 != (Object)null && component2.grabbed) { DebugLog("Saving carried item during level transition: " + name); } if ((Object)(object)StatsManager.instance == (Object)null) { DebugLog("StatsManager null during ChangeLevel save, skipping " + name); continue; } StatsManager.instance.ItemPurchase(name); hashSet.Add(name); num++; } } Logger.LogInfo((object)$"Fallback saved {num} unique items"); } } 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.8.0"; } }