Decompiled source of WeaponSpawner v1.4.1

WeaponSpawner.dll

Decompiled 6 days ago
using 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 System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("Adir")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.1.0")]
[assembly: AssemblyInformationalVersion("1.4.1")]
[assembly: AssemblyProduct("WeaponSpawner")]
[assembly: AssemblyTitle("WeaponSpawner")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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;
		}
	}
	[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;
		}
	}
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute(string assemblyName) : Attribute()
	{
		public string AssemblyName { get; } = assemblyName;
	}
}
namespace WeaponSpawner
{
	internal static class HostSpawner
	{
		private static readonly Dictionary<int, float> lastSpawn = new Dictionary<int, float>();

		private static readonly List<EnemyParent> spawnedMonsters = new List<EnemyParent>();

		public static void Handle(int sender, SpawnKind kind, string key, Vector3 position)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			string error = Check(sender, kind);
			if (error != null)
			{
				Reply(sender, ok: false, error);
				return;
			}
			switch (kind)
			{
			case SpawnKind.ResetKept:
			{
				int num = KeptItems.Reset();
				Reply(sender, ok: true, (num == 0) ? "No spawned items to reset" : $"Reset {num} spawned item(s). They won't come back next level");
				return;
			}
			case SpawnKind.RemoveMonsters:
				Reply(sender, ok: true, $"Removed {RemoveMonsters()} monster(s)");
				return;
			}
			if (sender != Net.LocalActor && Time.time - lastSpawn.GetValueOrDefault(sender, -999f) < WeaponSpawner.cooldown.Value)
			{
				Reply(sender, ok: false, "Slow down a bit");
				return;
			}
			string text = kind switch
			{
				SpawnKind.Item => SpawnItem(key, position, out error), 
				SpawnKind.Monster => SpawnMonster(key, position, out error), 
				_ => SpawnSpawnable(kind, key, position, out error), 
			};
			if (text == null)
			{
				Reply(sender, ok: false, error);
				return;
			}
			lastSpawn[sender] = Time.time;
			WeaponSpawner.Logger.LogInfo((object)$"Spawned {key} for player {sender}");
			Reply(sender, ok: true, "Spawned " + text);
		}

		private static string? Check(int sender, SpawnKind kind)
		{
			if (sender != Net.LocalActor && !WeaponSpawner.allowClients.Value)
			{
				return "The host has turned off spawning for other players";
			}
			if (!WeaponSpawner.InGame())
			{
				return "Can't do that right now";
			}
			if (kind == SpawnKind.Monster && !SemiFunc.RunIsLevel())
			{
				return "Monsters can only be spawned in a level";
			}
			return null;
		}

		private static void Reply(int sender, bool ok, string message)
		{
			Net.ToActor(sender, 182, new object[2] { ok, message });
		}

		private static string? SpawnItem(string key, Vector3 position, out string? error)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			if (!StatsManager.instance.itemDictionary.TryGetValue(key, out var value) || !Object.op_Implicit((Object)(object)value) || value.disabled)
			{
				error = "Unknown item " + key;
				return null;
			}
			KeptItems.Keep(Instantiate(value.prefab, position, value.spawnRotationOffset), value);
			return WeaponSpawner.DisplayName(value);
		}

		private static string? SpawnSpawnable(SpawnKind kind, string key, Vector3 position, out string? error)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			Spawnable spawnable = Spawnables.Find(key);
			if (spawnable == null || spawnable.Kind != kind)
			{
				error = "The host's game doesn't have that one";
				return null;
			}
			GameObject val = Instantiate(spawnable.Prefab, position, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
			ValuableObject val2 = default(ValuableObject);
			if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent<ValuableObject>(ref val2))
			{
				val2.DollarValueSetLogic();
			}
			return spawnable.Name;
		}

		private static string? SpawnMonster(string key, Vector3 position, out string? error)
		{
			//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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			Monster monster = Monsters.Find(key);
			if (monster == null)
			{
				error = "The host's game doesn't have that monster";
				return null;
			}
			LevelPoint val = (from p in SemiFunc.LevelPointsGetAll()
				where Object.op_Implicit((Object)(object)p)
				orderby Vector3.Distance(((Component)p).transform.position, position)
				select p).FirstOrDefault();
			if (!Object.op_Implicit((Object)(object)val))
			{
				error = "No spot to put a monster here";
				return null;
			}
			Vector3 position2 = ((Component)val).transform.position;
			spawnedMonsters.RemoveAll((EnemyParent m) => !Object.op_Implicit((Object)(object)m));
			EnemyParent val3 = default(EnemyParent);
			foreach (PrefabRef item in monster.Setup.spawnObjects.Where((PrefabRef p) => ((PrefabRef<GameObject>)(object)p)?.IsValid() ?? false))
			{
				GameObject val2 = Instantiate(item, position2, Quaternion.identity, EnemyFloaterHalloweenState.SpawnData(item));
				if (Object.op_Implicit((Object)(object)val2) && val2.TryGetComponent<EnemyParent>(ref val3))
				{
					val3.SetupDone = true;
					val3.firstSpawnPointUsed = true;
					Enemy componentInChildren = val2.GetComponentInChildren<Enemy>();
					if (componentInChildren != null)
					{
						componentInChildren.EnemyTeleported(position2);
					}
					spawnedMonsters.Add(val3);
				}
			}
			return monster.Name;
		}

		private static int RemoveMonsters()
		{
			int num = 0;
			foreach (EnemyParent item in spawnedMonsters.Where((EnemyParent m) => Object.op_Implicit((Object)(object)m)))
			{
				if (Object.op_Implicit((Object)(object)EnemyDirector.instance))
				{
					EnemyDirector.instance.enemiesSpawned.Remove(item);
				}
				if (Net.Multiplayer)
				{
					PhotonNetwork.Destroy(((Component)item).gameObject);
				}
				else
				{
					Object.Destroy((Object)(object)((Component)item).gameObject);
				}
				num++;
			}
			spawnedMonsters.Clear();
			return num;
		}

		private static GameObject Instantiate(PrefabRef prefab, Vector3 position, Quaternion rotation, object[]? data = null)
		{
			//IL_001b: 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_000d: 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)
			if (!Net.Multiplayer)
			{
				return Object.Instantiate<GameObject>(((PrefabRef<GameObject>)(object)prefab).Prefab, position, rotation);
			}
			return PhotonNetwork.InstantiateRoomObject(((PrefabRef<GameObject>)(object)prefab).ResourcePath, position, rotation, (byte)0, data);
		}
	}
	[HarmonyPatch]
	internal static class KeptItems
	{
		private const string StatName = "weaponSpawnerKept";

		private static readonly HashSet<ItemAttributes> pending = new HashSet<ItemAttributes>();

		private static Dictionary<string, int>? Names
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)StatsManager.instance))
				{
					return null;
				}
				SortedDictionary<string, Dictionary<string, int>> dictionaryOfDictionaries = StatsManager.instance.dictionaryOfDictionaries;
				if (!dictionaryOfDictionaries.TryGetValue("weaponSpawnerKept", out var value))
				{
					value = (dictionaryOfDictionaries["weaponSpawnerKept"] = new Dictionary<string, int>());
				}
				return value;
			}
		}

		public static int Count => Names?.Count((KeyValuePair<string, int> n) => StatsManager.instance.item.ContainsKey(n.Key)) ?? 0;

		public static void Keep(GameObject obj, Item item)
		{
			ItemAttributes item2 = default(ItemAttributes);
			if (WeaponSpawner.keepItems.Value && item.physicalItem && !SemiFunc.RunIsShop() && !SemiFunc.RunIsArena() && Object.op_Implicit((Object)(object)obj) && obj.TryGetComponent<ItemAttributes>(ref item2))
			{
				pending.Add(item2);
				int num = StatsManager.instance.itemsPurchased.GetValueOrDefault(((Object)item).name, 0) + 1;
				PunManager.instance.UpdateStat("itemsPurchased", ((Object)item).name, num);
			}
		}

		public static int Reset()
		{
			Dictionary<string, int> names = Names;
			if (names == null)
			{
				return 0;
			}
			int num = 0;
			foreach (string item in names.Keys.ToList())
			{
				if (StatsManager.instance.item.ContainsKey(item))
				{
					StatsManager.instance.ItemRemove(item);
					num++;
				}
			}
			names.Clear();
			pending.Clear();
			return num;
		}

		[HarmonyPatch(typeof(StatsManager), "ItemFetchName")]
		[HarmonyPostfix]
		private static void Named(ItemAttributes itemAttributes)
		{
			if (Object.op_Implicit((Object)(object)itemAttributes) && pending.Remove(itemAttributes) && !string.IsNullOrEmpty(itemAttributes.instanceName))
			{
				Dictionary<string, int> names = Names;
				if (names != null)
				{
					names[itemAttributes.instanceName] = 1;
				}
			}
		}

		[HarmonyPatch(typeof(StatsManager), "ItemRemove")]
		[HarmonyPostfix]
		private static void Removed(string instanceName)
		{
			if (instanceName != null)
			{
				Names?.Remove(instanceName);
			}
		}
	}
	internal sealed class Monster
	{
		public readonly EnemySetup Setup;

		public readonly string Name;

		public readonly string Group;

		public string Key => ((Object)Setup).name;

		public Monster(EnemySetup setup, string name, string group)
		{
			Setup = setup;
			Name = name;
			Group = group;
		}
	}
	internal static class Monsters
	{
		public static List<Monster> All()
		{
			List<Monster> list = new List<Monster>();
			if (!Object.op_Implicit((Object)(object)EnemyDirector.instance))
			{
				return list;
			}
			List<EnemySetup>[] array = new List<EnemySetup>[3]
			{
				EnemyDirector.instance.enemiesDifficulty1,
				EnemyDirector.instance.enemiesDifficulty2,
				EnemyDirector.instance.enemiesDifficulty3
			};
			HashSet<string> seen = new HashSet<string>();
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] == null)
				{
					continue;
				}
				string group = $"Tier {i + 1}";
				list.AddRange(from s in array[i]
					where Object.op_Implicit((Object)(object)s) && s.spawnObjects != null && s.spawnObjects.Any((PrefabRef p) => ((PrefabRef<GameObject>)(object)p)?.IsValid() ?? false) && seen.Add(((Object)s).name)
					select new Monster(s, Name(s), @group) into m
					orderby m.Name
					select m);
			}
			return list;
		}

		public static Monster? Find(string key)
		{
			return All().FirstOrDefault((Monster m) => m.Key == key);
		}

		private static string Name(EnemySetup setup)
		{
			List<string> list = (from p in setup.spawnObjects
				where p != null && ((PrefabRef<GameObject>)(object)p).IsValid() && Object.op_Implicit((Object)(object)((PrefabRef<GameObject>)(object)p).Prefab)
				select ((PrefabRef<GameObject>)(object)p).Prefab.GetComponent<EnemyParent>() into e
				where Object.op_Implicit((Object)(object)e) && !string.IsNullOrEmpty(e.enemyName)
				select e.enemyName).ToList();
			if (list.Count == 0)
			{
				return Regex.Replace(((Object)setup).name, "^Enemy (- )?", "");
			}
			return string.Join(" + ", from n in list
				group n by n into g
				select (g.Count() <= 1) ? g.Key : $"{g.Key} x{g.Count()}");
		}
	}
	internal enum SpawnKind
	{
		Item,
		Valuable,
		Cosmetic,
		Monster,
		ResetKept,
		RemoveMonsters
	}
	internal sealed class Spawnable
	{
		public readonly SpawnKind Kind;

		public readonly PrefabRef Prefab;

		public readonly string Name;

		public readonly string Group;

		public string Tags { get; private set; }

		public string Key => ((PrefabRef<GameObject>)(object)Prefab).ResourcePath;

		public Spawnable(SpawnKind kind, PrefabRef prefab, string name, string group, string tags)
		{
			Kind = kind;
			Prefab = prefab;
			Name = name;
			Group = group;
			Tags = tags;
		}

		public void AddTag(string tag)
		{
			if (!Tags.Contains(tag))
			{
				Tags = Tags + " " + tag;
			}
		}
	}
	internal static class Spawnables
	{
		private static readonly string[] SizeOrder = new string[7] { "tiny", "small", "medium", "big", "wide", "tall", "very tall" };

		private static readonly Dictionary<Rarity, PrefabRef> cosmeticBoxes = new Dictionary<Rarity, PrefabRef>();

		public static List<Spawnable> All()
		{
			List<Spawnable> list = CosmeticBoxes().ToList();
			if (!Object.op_Implicit((Object)(object)RunManager.instance))
			{
				return list;
			}
			Dictionary<string, (Spawnable, int)> dictionary = new Dictionary<string, (Spawnable, int)>();
			foreach (Level item in RunManager.instance.levels.Where((Level l) => Object.op_Implicit((Object)(object)l)))
			{
				string text = (string.IsNullOrEmpty(item.NarrativeName) ? ((Object)item).name.Replace("Level - ", "") : item.NarrativeName);
				foreach (LevelValuables item2 in item.ValuablePresets.Where((LevelValuables p) => Object.op_Implicit((Object)(object)p)))
				{
					List<PrefabRef>[] array = new List<PrefabRef>[7] { item2.tiny, item2.small, item2.medium, item2.big, item2.wide, item2.tall, item2.veryTall };
					for (int num = 0; num < array.Length; num++)
					{
						if (array[num] == null)
						{
							continue;
						}
						foreach (PrefabRef item3 in array[num].Where((PrefabRef r) => ((PrefabRef<GameObject>)(object)r)?.IsValid() ?? false))
						{
							if (dictionary.TryGetValue(((PrefabRef<GameObject>)(object)item3).ResourcePath, out var value))
							{
								value.Item1.AddTag(text);
								continue;
							}
							string name = Regex.Replace(((PrefabRef<GameObject>)(object)item3).PrefabName, "^Valuable ", "");
							string text2 = "Valuables - " + SizeOrder[num];
							dictionary[((PrefabRef<GameObject>)(object)item3).ResourcePath] = (new Spawnable(SpawnKind.Valuable, item3, name, text2, text), num);
						}
					}
				}
			}
			list.AddRange(from v in dictionary.Values
				orderby v.size, v.spawnable.Name
				select v.spawnable);
			return list;
		}

		public static Spawnable? Find(string key)
		{
			return All().FirstOrDefault((Spawnable s) => s.Key == key);
		}

		private static IEnumerable<Spawnable> CosmeticBoxes()
		{
			if (Object.op_Implicit((Object)(object)ValuableDirector.instance) && ValuableDirector.instance.cosmeticWorldObjectSetups != null)
			{
				foreach (CosmeticWorldObjectSetup cosmeticWorldObjectSetup in ValuableDirector.instance.cosmeticWorldObjectSetups)
				{
					if (cosmeticWorldObjectSetup?.prefab != null && ((PrefabRef<GameObject>)(object)cosmeticWorldObjectSetup.prefab).IsValid())
					{
						cosmeticBoxes[cosmeticWorldObjectSetup.rarity] = cosmeticWorldObjectSetup.prefab;
					}
				}
			}
			foreach (KeyValuePair<Rarity, PrefabRef> item in cosmeticBoxes.OrderBy<KeyValuePair<Rarity, PrefabRef>, Rarity>((KeyValuePair<Rarity, PrefabRef> p) => p.Key))
			{
				string text = (((int)item.Key == 3) ? "Ultra rare" : ((object)item.Key/*cast due to .constrained prefix*/).ToString());
				yield return new Spawnable(SpawnKind.Cosmetic, item.Value, text + " cosmetic box", "Cosmetic boxes", "cosmetic");
			}
		}
	}
	[HarmonyPatch(typeof(CosmeticWorldObject), "ExtractRPC")]
	internal static class CosmeticExtractPatch
	{
		private static void Prefix(out CosmeticWorldObjectDebug? __state)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (WeaponSpawner.uncapCosmeticBoxes.Value && Object.op_Implicit((Object)(object)ValuableDirector.instance))
			{
				__state = ValuableDirector.instance.cosmeticWorldObjectDebug;
				ValuableDirector.instance.cosmeticWorldObjectDebug = (CosmeticWorldObjectDebug)1;
			}
		}

		private static void Finalizer(CosmeticWorldObjectDebug? __state)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (__state.HasValue && Object.op_Implicit((Object)(object)ValuableDirector.instance))
			{
				ValuableDirector.instance.cosmeticWorldObjectDebug = __state.Value;
			}
		}
	}
	internal sealed class SpawnMenu : MonoBehaviour
	{
		private const float ReplyTimeout = 3f;

		private static readonly string[] Tabs = new string[4] { "Weapons", "Spawnables", "Monsters", "Settings" };

		private bool open;

		private int tab;

		private List<Item> items = new List<Item>();

		private List<Spawnable> spawnables = new List<Spawnable>();

		private List<Monster> monsters = new List<Monster>();

		private readonly Vector2[] scroll = (Vector2[])(object)new Vector2[Tabs.Length];

		private string filter = "";

		private Rect window = new Rect(40f, 40f, 360f, 560f);

		private string status = "";

		private Color statusColor = Color.white;

		private float statusUntil;

		private float waitingSince = -1f;

		private void Awake()
		{
			Net.Received += OnEvent;
		}

		private void Update()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Net.Hook();
			if (waitingSince >= 0f && Time.time - waitingSince > 3f)
			{
				waitingSince = -1f;
				SetStatus("No answer. Does the host have WeaponSpawner installed?", Color.yellow);
			}
			if (!Object.op_Implicit((Object)(object)ChatManager.instance) || !ChatManager.instance.chatActive)
			{
				KeyboardShortcut value = WeaponSpawner.menuKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					open = !open && WeaponSpawner.InGame();
					if (open)
					{
						items = WeaponSpawner.Spawnable();
						spawnables = Spawnables.All();
						monsters = Monsters.All();
					}
				}
			}
			if (open && !WeaponSpawner.InGame())
			{
				open = false;
			}
			if (open)
			{
				if (Object.op_Implicit((Object)(object)CursorManager.instance))
				{
					CursorManager.instance.Unlock(0.1f);
				}
				if (Object.op_Implicit((Object)(object)InputManager.instance))
				{
					InputManager.instance.DisableAiming(0.1f);
					InputManager.instance.DisableMovement(0.1f);
				}
			}
		}

		private void OnEvent(byte code, object? data, int sender)
		{
			//IL_0071: 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)
			//IL_007a: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			switch (code)
			{
			case 181:
				if (Net.IsHost && data is object[] array2 && array2.Length == 3 && array2[0] is int kind && array2[1] is string key && array2[2] is Vector3 position)
				{
					HostSpawner.Handle(sender, (SpawnKind)kind, key, position);
				}
				break;
			case 182:
				if (Net.FromHost(sender) && data is object[] array && array.Length == 2 && array[0] is bool flag && array[1] is string text)
				{
					waitingSince = -1f;
					SetStatus(text, (Color)(flag ? Color.green : new Color(1f, 0.45f, 0.45f)));
				}
				break;
			}
		}

		private void SetStatus(string text, Color color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			status = text;
			statusColor = color;
			statusUntil = Time.time + 4f;
		}

		private static Vector3 SpawnPoint(float distance)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if (!Object.op_Implicit((Object)(object)main))
			{
				if (!Object.op_Implicit((Object)(object)PlayerAvatar.instance))
				{
					return Vector3.zero;
				}
				return ((Component)PlayerAvatar.instance).transform.position + Vector3.up;
			}
			Vector3 position = ((Component)main).transform.position;
			Vector3 forward = ((Component)main).transform.forward;
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(position, forward, ref val, distance, -1, (QueryTriggerInteraction)1))
			{
				distance = Mathf.Max(0.3f, ((RaycastHit)(ref val)).distance - 0.4f);
			}
			return position + forward * distance;
		}

		private void Spawn(SpawnKind kind, string key)
		{
			//IL_002c: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!Net.IsHost)
			{
				waitingSince = Time.time;
			}
			Vector3 val = SpawnPoint(kind switch
			{
				SpawnKind.Monster => 4f, 
				SpawnKind.Item => 1.5f, 
				_ => 2.2f, 
			});
			Net.ToHost(181, new object[3]
			{
				(int)kind,
				key,
				val
			});
		}

		private void OnGUI()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!open)
			{
				if (Time.time < statusUntil)
				{
					DrawToast();
				}
			}
			else
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
				window = GUILayout.Window(387728, window, new WindowFunction(DrawWindow), "Item Spawner", Array.Empty<GUILayoutOption>());
			}
		}

		private void DrawToast()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			GUIStyle val = new GUIStyle(GUI.skin.box)
			{
				fontSize = 16
			};
			val.normal.textColor = statusColor;
			GUI.Box(new Rect((float)Screen.width / 2f - 220f, (float)(Screen.height - 120), 440f, 32f), status, val);
		}

		private bool Matches(string text)
		{
			return text.Replace('_', ' ').IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static void Header(string group, ref string? last)
		{
			if (!(group == last))
			{
				GUILayout.Label("<b>" + group.Replace('_', ' ').ToUpperInvariant() + "</b>", Array.Empty<GUILayoutOption>());
				last = group;
			}
		}

		private void DrawWindow(int id)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_00f4: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			tab = GUILayout.Toolbar(tab, Tabs, Array.Empty<GUILayoutOption>());
			if (tab != 3)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
				filter = GUILayout.TextField(filter, Array.Empty<GUILayoutOption>());
				GUILayout.EndHorizontal();
			}
			scroll[tab] = GUILayout.BeginScrollView(scroll[tab], Array.Empty<GUILayoutOption>());
			switch (tab)
			{
			case 0:
				DrawItems();
				break;
			case 1:
				DrawSpawnables();
				break;
			case 2:
				DrawMonsters();
				break;
			default:
				DrawSettings();
				break;
			}
			GUILayout.EndScrollView();
			if (Time.time < statusUntil)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					wordWrap = true
				};
				val.normal.textColor = statusColor;
				GUILayout.Label(status, val, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Label($"{WeaponSpawner.menuKey.Value} to close", Array.Empty<GUILayoutOption>());
			GUI.DragWindow();
		}

		private void DrawItems()
		{
			string last = null;
			foreach (Item item in items)
			{
				if (!Object.op_Implicit((Object)(object)item))
				{
					continue;
				}
				string text = WeaponSpawner.DisplayName(item);
				string text2 = ((object)Unsafe.As<itemType, itemType>(ref item.itemType)/*cast due to .constrained prefix*/).ToString();
				if (filter.Length <= 0 || Matches(text) || Matches(text2))
				{
					Header(text2, ref last);
					if (GUILayout.Button(text, Array.Empty<GUILayoutOption>()))
					{
						Spawn(SpawnKind.Item, ((Object)item).name);
					}
				}
			}
		}

		private void DrawSpawnables()
		{
			if (spawnables.Count == 0)
			{
				GUILayout.Label("Nothing found yet. Try again once you're in a level.", Array.Empty<GUILayoutOption>());
			}
			string last = null;
			foreach (Spawnable spawnable in spawnables)
			{
				if (filter.Length <= 0 || Matches(spawnable.Name) || Matches(spawnable.Group) || Matches(spawnable.Tags))
				{
					Header(spawnable.Group, ref last);
					if (GUILayout.Button(spawnable.Name, Array.Empty<GUILayoutOption>()))
					{
						Spawn(spawnable.Kind, spawnable.Key);
					}
				}
			}
		}

		private void DrawMonsters()
		{
			if (!SemiFunc.RunIsLevel())
			{
				GUILayout.Label("Monsters can only be spawned in a level, not the truck or shop.", Array.Empty<GUILayoutOption>());
				return;
			}
			if (monsters.Count == 0)
			{
				GUILayout.Label("No monsters found.", Array.Empty<GUILayoutOption>());
			}
			GUILayout.Label("They show up at the nearest open spot to where you're looking, and they're hostile.", Array.Empty<GUILayoutOption>());
			string last = null;
			foreach (Monster monster in monsters)
			{
				if (filter.Length <= 0 || Matches(monster.Name) || Matches(monster.Group))
				{
					Header(monster.Group, ref last);
					if (GUILayout.Button(monster.Name, Array.Empty<GUILayoutOption>()))
					{
						Spawn(SpawnKind.Monster, monster.Key);
					}
				}
			}
		}

		private void DrawSettings()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				wordWrap = true
			};
			GUILayout.Label("<b>SPAWNED ITEMS</b>", Array.Empty<GUILayoutOption>());
			if (Net.IsHost)
			{
				WeaponSpawner.keepItems.Value = GUILayout.Toggle(WeaponSpawner.keepItems.Value, " Keep spawned items in the truck next level", Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Spawned items in the truck list: {KeptItems.Count}", val, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.Label("The host decides whether spawned items come back in the truck.", val, Array.Empty<GUILayoutOption>());
			}
			if (GUILayout.Button("Reset spawned items", Array.Empty<GUILayoutOption>()))
			{
				Spawn(SpawnKind.ResetKept, "");
			}
			GUILayout.Label("Takes every spawned item off the truck list, so they don't come back next level. The ones lying around now stay until this level ends. Bought items aren't touched.", val, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.Label("<b>MONSTERS</b>", Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Remove spawned monsters", Array.Empty<GUILayoutOption>()))
			{
				Spawn(SpawnKind.RemoveMonsters, "");
			}
			GUILayout.Label("Removes the monsters spawned from this menu. The level's own monsters stay.", val, Array.Empty<GUILayoutOption>());
		}
	}
	public enum ItemList
	{
		Weapons,
		Shop,
		All
	}
	[BepInPlugin("Adir.WeaponSpawner", "WeaponSpawner", "1.4.1")]
	public class WeaponSpawner : BaseUnityPlugin
	{
		internal static ConfigEntry<KeyboardShortcut> menuKey;

		internal static ConfigEntry<bool> allowClients;

		internal static ConfigEntry<ItemList> itemList;

		internal static ConfigEntry<float> cooldown;

		internal static ConfigEntry<bool> uncapCosmeticBoxes;

		internal static ConfigEntry<bool> keepItems;

		internal static WeaponSpawner Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		private void Awake()
		{
			//IL_003e: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			menuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "MenuKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Opens and closes the spawn menu");
			itemList = ((BaseUnityPlugin)this).Config.Bind<ItemList>("General", "Items", ItemList.Shop, "Which items the menu lists. Weapons = guns, melee, launchers, grenades, mines. Shop = everything the shop or upgrade stand can sell (weapons, upgrades, health packs, crystals, drones, carts, trackers...). All = every item in the game, including ones the shop never sells");
			allowClients = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "AllowClientSpawns", true, "When you're the host: let other players with this mod spawn items too");
			cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Host", "ClientCooldown", 0.5f, "When you're the host: seconds a player has to wait between spawns");
			keepItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Host", "KeepSpawnedItems", true, "When you're the host: items spawned in a level count as bought, so they show up in the truck next level like shop items do. Not applied to items spawned in the shop");
			uncapCosmeticBoxes = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawnables", "UncapCosmeticBoxes", true, "The game only counts as many extracted cosmetic boxes per level as it would spawn on its own. With this on, every box you extract counts. It's checked on each player's own game");
			Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
			val.PatchAll(typeof(CosmeticExtractPatch));
			val.PatchAll(typeof(KeptItems));
			GameObject val2 = new GameObject("WeaponSpawner Menu");
			Object.DontDestroyOnLoad((Object)val2);
			((Object)val2).hideFlags = (HideFlags)61;
			val2.AddComponent<SpawnMenu>();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal static bool IsWeapon(Item item)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected I4, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			itemType itemType = item.itemType;
			switch (itemType - 6)
			{
			default:
				if ((int)itemType != 15)
				{
					break;
				}
				goto case 0;
			case 0:
			case 1:
			case 3:
			case 5:
				return true;
			case 2:
			case 4:
				break;
			}
			return false;
		}

		internal static bool IsBuyable(Item item)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			if (item.maxAmountInShop <= 0)
			{
				return (int)item.itemType == 3;
			}
			return true;
		}

		internal static bool Listed(Item item)
		{
			return itemList.Value switch
			{
				ItemList.Weapons => IsWeapon(item), 
				ItemList.Shop => IsBuyable(item), 
				_ => true, 
			};
		}

		internal static List<Item> Spawnable()
		{
			if (!Object.op_Implicit((Object)(object)StatsManager.instance))
			{
				return new List<Item>();
			}
			return (from i in StatsManager.instance.itemDictionary.Values.Where((Item i) => Object.op_Implicit((Object)(object)i) && !i.disabled && i.prefab != null && ((PrefabRef<GameObject>)(object)i.prefab).IsValid()).Where(Listed)
				orderby ((object)Unsafe.As<itemType, itemType>(ref i.itemType)/*cast due to .constrained prefix*/).ToString()
				select i).ThenBy(DisplayName).ToList();
		}

		internal static string DisplayName(Item item)
		{
			if (!string.IsNullOrEmpty(item.itemName) && !(item.itemName == "N/A"))
			{
				return item.itemName;
			}
			return ((Object)item).name.Replace("Item ", "");
		}

		internal static bool InGame()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			if (Object.op_Implicit((Object)(object)RunManager.instance) && Object.op_Implicit((Object)(object)GameManager.instance) && Object.op_Implicit((Object)(object)GameDirector.instance) && Object.op_Implicit((Object)(object)LevelGenerator.Instance) && LevelGenerator.Instance.Generated && (int)GameDirector.instance.currentState == 2 && !SemiFunc.MenuLevel())
			{
				return !SemiFunc.RunIsLobbyMenu();
			}
			return false;
		}
	}
	internal static class Net
	{
		public const byte Request = 181;

		public const byte Reply = 182;

		private static bool hooked;

		public static bool Multiplayer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)GameManager.instance))
				{
					return SemiFunc.IsMultiplayer();
				}
				return false;
			}
		}

		public static bool IsHost => SemiFunc.IsMasterClientOrSingleplayer();

		public static int LocalActor
		{
			get
			{
				if (!Multiplayer || PhotonNetwork.LocalPlayer == null)
				{
					return 1;
				}
				return PhotonNetwork.LocalPlayer.ActorNumber;
			}
		}

		public static event Action<byte, object?, int>? Received;

		public static void Hook()
		{
			if (!hooked && PhotonNetwork.NetworkingClient != null)
			{
				PhotonNetwork.NetworkingClient.EventReceived += OnEvent;
				hooked = true;
			}
		}

		private static void OnEvent(EventData e)
		{
			if (e.Code != 181 && e.Code != 182)
			{
				return;
			}
			try
			{
				Net.Received?.Invoke(e.Code, e.CustomData, e.Sender);
			}
			catch (Exception arg)
			{
				WeaponSpawner.Logger.LogError((object)$"Spawner event {e.Code} failed: {arg}");
			}
		}

		public static void ToHost(byte code, object? data)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (!Multiplayer || IsHost)
			{
				Net.Received?.Invoke(code, data, LocalActor);
				return;
			}
			PhotonNetwork.RaiseEvent(code, data, new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)2
			}, SendOptions.SendReliable);
		}

		public static void ToActor(int actor, byte code, object? data)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!Multiplayer || actor == LocalActor)
			{
				Net.Received?.Invoke(code, data, LocalActor);
				return;
			}
			RaiseEventOptions val = new RaiseEventOptions();
			val.TargetActors = new int[1] { actor };
			PhotonNetwork.RaiseEvent(code, data, val, SendOptions.SendReliable);
		}

		public static bool FromHost(int sender)
		{
			if (Multiplayer)
			{
				if (PhotonNetwork.MasterClient != null)
				{
					return PhotonNetwork.MasterClient.ActorNumber == sender;
				}
				return false;
			}
			return true;
		}
	}
}