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.2.0
plugins/REPO_All_Shop_Items_in_Level.dll
Decompiled 2 weeks 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] [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.23")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(EnemyParent), "Despawn")] private class DespawnPatch { private static int GetSpawnValuableCurrent(EnemyParent ep) { object? obj = AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(ep); Enemy val = (Enemy)((obj is Enemy) ? obj : null); if ((Object)(object)val == (Object)null) { return 0; } object? obj2 = AccessTools.Field(typeof(Enemy), "Health")?.GetValue(val); EnemyHealth val2 = (EnemyHealth)((obj2 is EnemyHealth) ? obj2 : null); if ((Object)(object)val2 == (Object)null) { return 0; } FieldInfo fieldInfo = AccessTools.Field(typeof(EnemyHealth), "spawnValuableCurrent"); return (!(fieldInfo == null)) ? ((int)fieldInfo.GetValue(val2)) : 0; } private static void Prefix(EnemyParent __instance, out int __state) { __state = GetSpawnValuableCurrent(__instance); } private static void Postfix(EnemyParent __instance, int __state) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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) && GetRandomItemOfType((itemType)8, out var item)) { object? obj = AccessTools.Field(typeof(EnemyParent), "Enemy")?.GetValue(__instance); Enemy val = (Enemy)((obj is Enemy) ? obj : null); Transform val2 = (Object.op_Implicit((Object)(object)val.CustomValuableSpawnTransform) ? val.CustomValuableSpawnTransform : val.CenterTransform); SpawnItem(item, val2.position + Vector3.up, 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>(); } } } [CompilerGenerated] private sealed class <PopulateAllowListWhenReady>d__28 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private Dictionary<string, Item>.ValueCollection.Enumerator <>s__1; private Item <value>5__2; private int <t>5__3; private string <section>5__4; private string <key>5__5; private ConfigEntry<bool> <entry>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PopulateAllowListWhenReady>d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>s__1 = default(Dictionary<string, Item>.ValueCollection.Enumerator); <value>5__2 = null; <section>5__4 = null; <key>5__5 = null; <entry>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected I4, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null || StatsManager.instance.itemDictionary.Count == 0) { <>2__current = null; <>1__state = 1; return true; } if (ItemAllowList != null) { return false; } Logger.LogInfo((object)"Initializing per-item allow list"); ItemAllowList = new Dictionary<string, ConfigEntry<bool>>(); <>s__1 = StatsManager.instance.itemDictionary.Values.GetEnumerator(); try { while (<>s__1.MoveNext()) { <value>5__2 = <>s__1.Current; <t>5__3 = (int)<value>5__2.itemType; <section>5__4 = ((<t>5__3 == 0) ? "6_AllowedItems_Drones" : ((<t>5__3 == 3) ? "6_AllowedItems_Upgrades" : ((<t>5__3 == 8) ? null : "6_AllowedItems_OtherShop"))); if (<section>5__4 != null) { <key>5__5 = ((Object)<value>5__2).name; <entry>5__6 = ((BaseUnityPlugin)Instance).Config.Bind<bool>(<section>5__4, <key>5__5, true, "Allow '" + <key>5__5 + "' to spawn"); ItemAllowList[<key>5__5] = <entry>5__6; DebugLog("Registered: " + <key>5__5); <section>5__4 = null; <key>5__5 = null; <entry>5__6 = null; <value>5__2 = null; } } } finally { ((IDisposable)<>s__1).Dispose(); } <>s__1 = default(Dictionary<string, Item>.ValueCollection.Enumerator); Logger.LogInfo((object)$"Registered {ItemAllowList.Count} items"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } 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 Dictionary<string, ConfigEntry<bool>> ItemAllowList; private static readonly HashSet<int> KnownSpecialTypes = new HashSet<int> { 0, 3, 8 }; 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 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 (even if not in the truck). This ensures no item is lost."); SpawnUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "SpawnUpgradeItems", true, ""); MapHideUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "MapHideUpgradeItems", false, ""); UpgradeItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("1_UpgradeItems", "UpgradeItemSpawnChance", 2.5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForUpgradeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("1_UpgradeItems", "UseShopPriceForItemSelection", true, ""); SpawnDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "SpawnDroneItems", true, ""); MapHideDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "MapHideDroneItems", false, ""); DroneItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("2_DroneItems", "DroneItemsSpawnChance", 0.95f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForDroneItems = ((BaseUnityPlugin)this).Config.Bind<bool>("2_DroneItems", "UseShopPriceForItemSelection", true, ""); SpawnOtherShopItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "SpawnOtherShopItems", true, ""); MapHideOtherShopItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "MapHideOtherShopItems", false, ""); OtherShopItemSpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("3_OtherShopItems", "OtherShopItemSpawnChance", 1.5f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); UseShopPriceForOtherItems = ((BaseUnityPlugin)this).Config.Bind<bool>("3_OtherShopItems", "UseShopPriceForItemSelection", true, ""); SpawnHealthPacksFromEnemies = ((BaseUnityPlugin)this).Config.Bind<bool>("4_HealthPacks", "SpawnHealthPacksFromEnemies", true, ""); HealthPackDropChance = ((BaseUnityPlugin)this).Config.Bind<float>("4_HealthPacks", "HealthPackDropChance", 100f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); MinItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MinItemValue", 0f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemValue = ((BaseUnityPlugin)this).Config.Bind<float>("5_Filters", "MaxItemValue", 0f, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 999999f), Array.Empty<object>())); MaxItemsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("5_Filters", "MaxItemsPerLevel", 0, new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); ((MonoBehaviour)this).StartCoroutine(PopulateAllowListWhenReady()); } [IteratorStateMachine(typeof(<PopulateAllowListWhenReady>d__28))] private IEnumerator PopulateAllowListWhenReady() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PopulateAllowListWhenReady>d__28(0) { <>4__this = this }; } 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) { if (ItemAllowList == null) { return true; } string name = ((Object)item).name; ConfigEntry<bool> value; return !ItemAllowList.TryGetValue(name, out value) || value.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).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) { 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) item = null; List<Item> candidates = GetCandidates((Item i) => i.itemType == type); if (candidates.Count == 0) { return false; } item = candidates[Random.Range(0, candidates.Count)]; return true; } private static bool GetRandomOtherShopItem(out Item item) { item = null; List<Item> candidates = GetCandidates((Item i) => !KnownSpecialTypes.Contains((int)i.itemType)); if (candidates.Count == 0) { return false; } item = WeightedOrRandom(candidates, UseShopPriceForOtherItems.Value); return (Object)(object)item != (Object)null; } 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 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 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() { 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} volumes (upgrade:{UpgradeItemSpawnChance.Value}%, drone:{DroneItemSpawnChance.Value}%, other:{OtherShopItemSpawnChance.Value}%)"); int value = MaxItemsPerLevel.Value; int num = 0; foreach (ValuableVolume item in list) { if (value > 0 && num >= value) { break; } if (RandomItemSpawn(item)) { num++; } } Logger.LogInfo((object)$"Spawned {num} items total"); } [HarmonyPatch(typeof(Map), "AddCustom")] [HarmonyPostfix] public static void Map_AddCustom_Postfix(MapCustom mapCustom) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected I4, but got Unknown ItemAttributes val = default(ItemAttributes); if (SemiFunc.RunIsLevel() && ((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; } SpawnedItemTracker[] array = Object.FindObjectsOfType<SpawnedItemTracker>(false); int num = 0; SpawnedItemTracker[] array2 = array; foreach (SpawnedItemTracker spawnedItemTracker in array2) { GameObject gameObject = ((Component)spawnedItemTracker).gameObject; bool flag = false; RoomVolumeCheck component = gameObject.GetComponent<RoomVolumeCheck>(); if ((Object)(object)component != (Object)null && component.CurrentRooms.Any((RoomVolume r) => r.Extraction)) { flag = true; DebugLog("Item " + ((Object)gameObject).name + " is inside extraction zone"); } PhysGrabObject component2 = gameObject.GetComponent<PhysGrabObject>(); if ((Object)(object)component2 != (Object)null && component2.grabbed) { flag = true; DebugLog("Item " + ((Object)gameObject).name + " is grabbed by a player"); } if (!flag) { continue; } ItemAttributes component3 = gameObject.GetComponent<ItemAttributes>(); if ((Object)(object)component3 == (Object)null || (Object)(object)component3.item == (Object)null) { DebugLog("Item " + ((Object)gameObject).name + " has no ItemAttributes, skipping"); continue; } string name = ((Object)component3.item).name; Logger.LogInfo((object)("Saving extracted item: " + name)); StatsManager.instance.ItemPurchase(name); PhysGrabObject component4 = gameObject.GetComponent<PhysGrabObject>(); if (component4 != null) { component4.DestroyPhysGrabObject(); } num++; } Logger.LogInfo((object)$"Saved {num} 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 completed. Saving {array.Length} remaining spawned items as purchased (fallback)"); int num = 0; SpawnedItemTracker[] array2 = array; foreach (SpawnedItemTracker spawnedItemTracker in array2) { GameObject gameObject = ((Component)spawnedItemTracker).gameObject; ItemAttributes component = gameObject.GetComponent<ItemAttributes>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.item == (Object)null)) { string name = ((Object)component.item).name; DebugLog("Fallback save: " + name); StatsManager.instance.ItemPurchase(name); num++; } } Logger.LogInfo((object)$"Fallback saved {num} 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.7.23"; } }