Decompiled source of RepoCommandConsole v2.0.0

RepoCommandConsole.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Modules;
using RepoLiveControl.Commands;
using RepoLiveControl.Networking;
using RepoLiveControl.Runtime;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RepoCommandConsole")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Host-authoritative R.E.P.O. command console with fuzzy autocomplete and delegated client permissions.")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+a45269048a6bbb6b3902670edb7323a8d213f586")]
[assembly: AssemblyProduct("RepoCommandConsole")]
[assembly: AssemblyTitle("RepoCommandConsole")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace RepoLiveControl
{
	internal sealed class CommandConsoleRuntime : IDisposable
	{
		private const string InputControlName = "RepoCommandConsole.Input";

		private const int WindowId = 198042;

		private const int SuggestionLimit = 8;

		private readonly Plugin plugin;

		private readonly ConfigEntry<KeyCode> toggleKey;

		private readonly ConfigEntry<int> networkEventCode;

		private readonly List<string> history = new List<string>();

		private readonly ConsoleInputGate inputGate = new ConsoleInputGate();

		private Rect windowRect;

		private string input = "/";

		private string result = "Ready. Type /help or use fuzzy autocomplete.";

		private IReadOnlyList<CompletionItem> suggestions = Array.AsReadOnly(new CompletionItem[0]);

		private CompletionCatalog catalog = CompletionCatalog.Empty;

		private int selectedSuggestion;

		private int pendingCaretPosition = -1;

		private int completionCaretPosition = 1;

		private bool open;

		private bool focusInput;

		private bool releaseGuiFocus;

		private bool stylesReady;

		private bool localPermissionKnown;

		private bool localPermissionGranted;

		private long observedPermissionSessionRevision;

		private float catalogRefreshAt;

		private GUIStyle windowStyle;

		private GUIStyle titleStyle;

		private GUIStyle hintStyle;

		private GUIStyle inputStyle;

		private GUIStyle suggestionStyle;

		private GUIStyle selectedSuggestionStyle;

		private GUIStyle resultStyle;

		private Texture2D windowBackground;

		private Texture2D selectedBackground;

		internal PermissionService Permissions { get; private set; }

		internal CommandNetworkRouter Network { get; private set; }

		internal string ToggleKeyLabel => ((object)toggleKey.Value/*cast due to .constrained prefix*/).ToString();

		internal CommandConsoleRuntime(Plugin plugin)
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			this.plugin = plugin;
			toggleKey = ((BaseUnityPlugin)plugin).Config.Bind<KeyCode>("Console", "ToggleKey", (KeyCode)283, "Key used to open and close the independent in-game command console.");
			networkEventCode = ((BaseUnityPlugin)plugin).Config.Bind<int>("Networking", "PhotonEventCode", 198, "Fixed Photon custom event code shared by all clients (3-199). Change only if another mod collides.");
			int num = Mathf.Clamp(networkEventCode.Value, 3, 199);
			if (num != networkEventCode.Value)
			{
				networkEventCode.Value = num;
				((BaseUnityPlugin)plugin).Config.Save();
			}
			Permissions = new PermissionService();
			observedPermissionSessionRevision = Permissions.SessionRevision;
			Network = new CommandNetworkRouter((byte)num, Permissions, SetResult);
			windowRect = new Rect(0f, 90f, 860f, 510f);
		}

		internal void Update()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Network.Update(IsNetworkSessionSceneActive());
			Bridge.PublishPermissionSessionRevision(Permissions.SessionRevision);
			if (observedPermissionSessionRevision != Permissions.SessionRevision)
			{
				observedPermissionSessionRevision = Permissions.SessionRevision;
				localPermissionKnown = false;
				localPermissionGranted = false;
			}
			if (inputGate.TryAccept(ConsoleInputAction.Toggle, Time.frameCount, Input.GetKeyDown(toggleKey.Value), IsInputSystemKeyPressedThisFrame(toggleKey.Value), guiPressedThisFrame: false))
			{
				SetOpen(!open);
			}
			else
			{
				if (!open)
				{
					return;
				}
				if (TryAcceptInputAction(ConsoleInputAction.Close, (KeyCode)27, (KeyCode)0))
				{
					SetOpen(value: false);
					return;
				}
				if (TryAcceptInputAction(ConsoleInputAction.AcceptCompletion, (KeyCode)9, (KeyCode)0))
				{
					AcceptSelectedSuggestion(appendSpace: true);
				}
				else if (TryAcceptInputAction(ConsoleInputAction.SelectPrevious, (KeyCode)273, (KeyCode)0) && suggestions.Count > 0)
				{
					selectedSuggestion = (selectedSuggestion - 1 + suggestions.Count) % suggestions.Count;
				}
				else if (TryAcceptInputAction(ConsoleInputAction.SelectNext, (KeyCode)274, (KeyCode)0) && suggestions.Count > 0)
				{
					selectedSuggestion = (selectedSuggestion + 1) % suggestions.Count;
				}
				else if (TryAcceptInputAction(ConsoleInputAction.Submit, (KeyCode)13, (KeyCode)271))
				{
					SubmitInput();
				}
				try
				{
					SemiFunc.InputDisableMovement();
					SemiFunc.InputDisableAiming();
					SemiFunc.CursorUnlock(0.1f);
					if ((Object)(object)MenuManager.instance != (Object)null)
					{
						MenuManager.instance.TextInputActive();
					}
					if ((Object)(object)PlayerController.instance != (Object)null)
					{
						PlayerController.instance.InputDisable(0.1f);
					}
				}
				catch
				{
				}
				if (Time.realtimeSinceStartup >= catalogRefreshAt)
				{
					RefreshCatalog();
					catalogRefreshAt = Time.realtimeSinceStartup + 1f;
				}
			}
		}

		internal void OnGUI()
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			ReleaseGuiFocusIfRequested();
			if (open)
			{
				EnsureStyles();
				float num = Mathf.Min(900f, Mathf.Max(540f, (float)Screen.width - 40f));
				((Rect)(ref windowRect)).width = num;
				((Rect)(ref windowRect)).height = Mathf.Min(600f, Mathf.Max(440f, (float)Screen.height - 120f));
				((Rect)(ref windowRect)).x = Mathf.Clamp(((Rect)(ref windowRect)).x, 10f, Mathf.Max(10f, (float)Screen.width - num - 10f));
				((Rect)(ref windowRect)).y = Mathf.Clamp(((Rect)(ref windowRect)).y, 10f, Mathf.Max(10f, (float)Screen.height - ((Rect)(ref windowRect)).height - 10f));
				if (((Rect)(ref windowRect)).x <= 0f)
				{
					((Rect)(ref windowRect)).x = ((float)Screen.width - num) * 0.5f;
				}
				HandleKeyboardEvent(Event.current);
				if (!open)
				{
					ReleaseGuiFocusIfRequested();
				}
				else
				{
					windowRect = GUI.Window(198042, windowRect, new WindowFunction(DrawWindow), string.Empty, windowStyle);
				}
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Invalid comparison between Unknown and I4
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Label("REPO COMMAND CONSOLE  •  " + RoleLabel(), titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label(ToggleKeyLabel + " / Esc closes  •  ↑↓ selects  •  Tab accepts  •  Enter runs", hintStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			GUI.SetNextControlName("RepoCommandConsole.Input");
			string a = GUILayout.TextField(input, inputStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(38f) });
			bool num = !string.Equals(a, input, StringComparison.Ordinal);
			if (num)
			{
				input = a;
			}
			if (focusInput)
			{
				GUI.FocusControl("RepoCommandConsole.Input");
				focusInput = false;
			}
			TextEditor focusedInputEditor = GetFocusedInputEditor();
			if (pendingCaretPosition >= 0 && focusedInputEditor != null && (int)Event.current.type == 7)
			{
				int selectIndex = (focusedInputEditor.cursorIndex = Mathf.Clamp(pendingCaretPosition, 0, input.Length));
				focusedInputEditor.selectIndex = selectIndex;
				pendingCaretPosition = -1;
			}
			int num3 = ((pendingCaretPosition >= 0) ? Mathf.Clamp(pendingCaretPosition, 0, input.Length) : ((focusedInputEditor != null) ? Mathf.Clamp(focusedInputEditor.cursorIndex, 0, input.Length) : Mathf.Clamp(completionCaretPosition, 0, input.Length)));
			bool flag = num3 != completionCaretPosition;
			completionCaretPosition = num3;
			if (num || flag)
			{
				selectedSuggestion = 0;
				RefreshSuggestions();
			}
			GUILayout.Space(6f);
			GUILayout.Label("FUZZY AUTOCOMPLETE", hintStyle, Array.Empty<GUILayoutOption>());
			if (suggestions.Count == 0)
			{
				GUILayout.Label("No completion for the active argument.", hintStyle, Array.Empty<GUILayoutOption>());
			}
			else
			{
				for (int i = 0; i < suggestions.Count; i++)
				{
					CompletionItem completionItem = suggestions[i];
					string obj = ((i == selectedSuggestion) ? "▶  " : "    ");
					GUIStyle val = ((i == selectedSuggestion) ? selectedSuggestionStyle : suggestionStyle);
					if (GUILayout.Button(obj + completionItem.Value, val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
					{
						selectedSuggestion = i;
						AcceptSelectedSuggestion(appendSpace: true);
					}
				}
			}
			GUILayout.FlexibleSpace();
			GUILayout.Label("RESULT", hintStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label(result, resultStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.MinHeight(48f),
				GUILayout.MaxHeight(72f)
			});
			if (history.Count > 0)
			{
				GUILayout.Label(string.Join("\n", history.ToArray()), hintStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MaxHeight(72f) });
			}
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Help", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				input = "/help";
				SubmitInput();
			}
			if (GUILayout.Button("Clear", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				input = "/";
				completionCaretPosition = input.Length;
				result = "Ready.";
				history.Clear();
				RefreshSuggestions();
				focusInput = true;
			}
			if (GUILayout.Button("Run", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				SubmitInput();
			}
			if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				SetOpen(value: false);
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref windowRect)).width, 44f));
		}

		private void HandleKeyboardEvent(Event current)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Invalid comparison between Unknown and I4
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Invalid comparison between Unknown and I4
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Invalid comparison between Unknown and I4
			if (current == null || (int)current.type != 4)
			{
				return;
			}
			if (current.keyCode == toggleKey.Value)
			{
				if (inputGate.TryAccept(ConsoleInputAction.Toggle, Time.frameCount, legacyPressedThisFrame: false, inputSystemPressedThisFrame: false, guiPressedThisFrame: true))
				{
					SetOpen(!open);
				}
				current.Use();
			}
			else if ((int)current.keyCode == 27)
			{
				if (AcceptGuiInput(ConsoleInputAction.Close))
				{
					SetOpen(value: false);
				}
				current.Use();
			}
			else if ((int)current.keyCode == 9)
			{
				if (AcceptGuiInput(ConsoleInputAction.AcceptCompletion))
				{
					AcceptSelectedSuggestion(appendSpace: true);
				}
				current.Use();
			}
			else if ((int)current.keyCode == 273 && suggestions.Count > 0)
			{
				if (AcceptGuiInput(ConsoleInputAction.SelectPrevious))
				{
					selectedSuggestion = (selectedSuggestion - 1 + suggestions.Count) % suggestions.Count;
				}
				current.Use();
			}
			else if ((int)current.keyCode == 274 && suggestions.Count > 0)
			{
				if (AcceptGuiInput(ConsoleInputAction.SelectNext))
				{
					selectedSuggestion = (selectedSuggestion + 1) % suggestions.Count;
				}
				current.Use();
			}
			else if ((int)current.keyCode == 13 || (int)current.keyCode == 271)
			{
				if (AcceptGuiInput(ConsoleInputAction.Submit))
				{
					SubmitInput();
				}
				current.Use();
			}
		}

		private static bool IsNetworkSessionSceneActive()
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return NetworkSessionSceneActivationPolicy.ShouldActivate(managerAvailable: false, currentLevelAvailable: false, isLobby: false, isGameplay: false, isShop: false, isArena: false);
			}
			Level levelCurrent = instance.levelCurrent;
			if ((Object)(object)levelCurrent == (Object)null)
			{
				return NetworkSessionSceneActivationPolicy.ShouldActivate(managerAvailable: true, currentLevelAvailable: false, isLobby: false, isGameplay: false, isShop: false, isArena: false);
			}
			return NetworkSessionSceneActivationPolicy.ShouldActivate(managerAvailable: true, currentLevelAvailable: true, (Object)(object)levelCurrent == (Object)(object)instance.levelLobby, ContainsLevel(instance.levels, levelCurrent), ContainsLevel(instance.levelShop, levelCurrent), ContainsLevel(instance.levelArena, levelCurrent));
		}

		private static bool ContainsLevel(IList<Level> levels, Level current)
		{
			return levels?.Contains(current) ?? false;
		}

		private bool TryAcceptInputAction(ConsoleInputAction action, KeyCode primaryKey, KeyCode secondaryKey = (KeyCode)0)
		{
			//IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			bool legacyPressedThisFrame = Input.GetKeyDown(primaryKey) || ((int)secondaryKey != 0 && Input.GetKeyDown(secondaryKey));
			bool inputSystemPressedThisFrame = IsInputSystemKeyPressedThisFrame(primaryKey) || ((int)secondaryKey != 0 && IsInputSystemKeyPressedThisFrame(secondaryKey));
			return inputGate.TryAccept(action, Time.frameCount, legacyPressedThisFrame, inputSystemPressedThisFrame, guiPressedThisFrame: false);
		}

		private bool AcceptGuiInput(ConsoleInputAction action)
		{
			return inputGate.TryAccept(action, Time.frameCount, legacyPressedThisFrame: false, inputSystemPressedThisFrame: false, guiPressedThisFrame: true);
		}

		private void SubmitInput()
		{
			string text = (input ?? string.Empty).Trim();
			CommandParseResult commandParseResult = SlashCommandParser.Parse(text);
			if (!commandParseResult.Success)
			{
				SetResult("ERROR " + commandParseResult.ErrorMessage);
				focusInput = true;
				return;
			}
			AddHistory("> " + text);
			result = "PENDING Sending command to " + ((!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient) ? "host executor..." : "lobby host...");
			try
			{
				if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient)
				{
					int requesterActorNumber = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : (-1));
					long requiredSessionRevision = Permissions.SessionRevision;
					Bridge.Enqueue(new ControlRequest(text, CommandRequestSource.LocalConsole, requesterActorNumber, SetResult, requiredSessionRevision, () => Permissions.SessionRevision == requiredSessionRevision));
				}
				else
				{
					Network.SendRequest(text);
				}
			}
			catch (Exception ex)
			{
				SetResult("ERROR " + ex.Message);
			}
			focusInput = true;
		}

		private void SetResult(string value)
		{
			result = (string.IsNullOrWhiteSpace(value) ? "ERROR Empty command response." : value);
			AddHistory(result);
			if (result.IndexOf("granted you", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				localPermissionKnown = true;
				localPermissionGranted = true;
			}
			else if (result.IndexOf("revoked your", StringComparison.OrdinalIgnoreCase) >= 0 || result.IndexOf("has not granted", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				localPermissionKnown = true;
				localPermissionGranted = false;
			}
			if (Plugin.Log != null)
			{
				Plugin.Log.LogInfo((object)("Console result: " + result));
			}
		}

		private void AddHistory(string value)
		{
			if (!string.IsNullOrWhiteSpace(value))
			{
				history.Insert(0, (value.Length > 140) ? (value.Substring(0, 140) + "…") : value);
				while (history.Count > 3)
				{
					history.RemoveAt(history.Count - 1);
				}
			}
		}

		private void AcceptSelectedSuggestion(bool appendSpace)
		{
			if (suggestions.Count != 0)
			{
				selectedSuggestion = Mathf.Clamp(selectedSuggestion, 0, suggestions.Count - 1);
				CompletionApplication completionApplication = CommandCompletionEngine.ApplyCompletion(input, suggestions[selectedSuggestion], appendSpace);
				input = completionApplication.Text;
				pendingCaretPosition = completionApplication.CaretPosition;
				completionCaretPosition = completionApplication.CaretPosition;
				selectedSuggestion = 0;
				RefreshSuggestions();
				focusInput = true;
			}
		}

		private void RefreshCatalog()
		{
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			bool flag = !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
			if (flag)
			{
				list.AddRange(Permissions.GetGrantCandidates());
				list2.AddRange(Permissions.GetRevokeCandidates());
			}
			catalog = new CompletionCatalog(RuntimeTargetCatalog.GetSelectors(includeAll: true), list, list2, flag);
			RefreshSuggestions();
		}

		private void RefreshSuggestions()
		{
			try
			{
				suggestions = CommandCompletionEngine.GetCompletions(input, Mathf.Clamp(completionCaretPosition, 0, (input != null) ? input.Length : 0), catalog, 8);
			}
			catch (Exception ex)
			{
				suggestions = Array.AsReadOnly(new CompletionItem[0]);
				if (Plugin.Log != null)
				{
					Plugin.Log.LogWarning((object)("Could not refresh command suggestions: " + ex.Message));
				}
			}
			if (selectedSuggestion >= suggestions.Count)
			{
				selectedSuggestion = 0;
			}
		}

		private string RoleLabel()
		{
			if (!PhotonNetwork.InRoom)
			{
				return "LOCAL HOST";
			}
			if (PhotonNetwork.IsMasterClient)
			{
				return "LOBBY HOST";
			}
			if (!localPermissionKnown)
			{
				return "CLIENT • PERMISSION UNKNOWN";
			}
			if (!localPermissionGranted)
			{
				return "CLIENT • NOT GRANTED";
			}
			return "CLIENT • PERMISSION GRANTED";
		}

		private void SetOpen(bool value)
		{
			open = value;
			if (open)
			{
				if (string.IsNullOrWhiteSpace(input))
				{
					input = "/";
				}
				((Rect)(ref windowRect)).x = ((float)Screen.width - ((Rect)(ref windowRect)).width) * 0.5f;
				((Rect)(ref windowRect)).y = Mathf.Max(20f, (float)Screen.height * 0.08f);
				focusInput = true;
				pendingCaretPosition = input.Length;
				completionCaretPosition = input.Length;
				releaseGuiFocus = false;
				RefreshCatalog();
				result = "Ready. Chat is not required; this console uses its own input path.";
			}
			else
			{
				releaseGuiFocus = true;
			}
			if (Plugin.Log != null)
			{
				Plugin.Log.LogInfo((object)("Command console " + (open ? "opened." : "closed.")));
			}
		}

		private static TextEditor GetFocusedInputEditor()
		{
			if (!string.Equals(GUI.GetNameOfFocusedControl(), "RepoCommandConsole.Input", StringComparison.Ordinal))
			{
				return null;
			}
			object stateObject = GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
			return (TextEditor)((stateObject is TextEditor) ? stateObject : null);
		}

		private unsafe static bool IsInputSystemKeyPressedThisFrame(KeyCode keyCode)
		{
			//IL_0027: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			Keyboard current = Keyboard.current;
			if (current == null)
			{
				return false;
			}
			if (!Enum.TryParse<Key>(ConsoleToggleKeyMapping.ToInputSystemKeyName(((object)(*(KeyCode*)(&keyCode))/*cast due to .constrained prefix*/).ToString()), ignoreCase: true, out Key val) || (int)val == 0)
			{
				return false;
			}
			if (current[val] != null)
			{
				return ((ButtonControl)current[val]).wasPressedThisFrame;
			}
			return false;
		}

		private void ReleaseGuiFocusIfRequested()
		{
			if (releaseGuiFocus)
			{
				GUI.FocusControl((string)null);
				releaseGuiFocus = false;
			}
		}

		private void EnsureStyles()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Expected O, but got Unknown
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Expected O, but got Unknown
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			if (!stylesReady)
			{
				stylesReady = true;
				windowBackground = MakeTexture(new Color(0.035f, 0.045f, 0.055f, 0.97f));
				selectedBackground = MakeTexture(new Color(0.16f, 0.24f, 0.19f, 0.98f));
				windowStyle = new GUIStyle(GUI.skin.window);
				windowStyle.normal.background = windowBackground;
				windowStyle.padding = new RectOffset(20, 20, 16, 18);
				titleStyle = new GUIStyle(GUI.skin.label);
				titleStyle.fontSize = 22;
				titleStyle.fontStyle = (FontStyle)1;
				titleStyle.normal.textColor = new Color(1f, 0.86f, 0.12f);
				hintStyle = new GUIStyle(GUI.skin.label);
				hintStyle.fontSize = 13;
				hintStyle.wordWrap = true;
				hintStyle.normal.textColor = new Color(0.72f, 0.78f, 0.8f);
				inputStyle = new GUIStyle(GUI.skin.textField);
				inputStyle.fontSize = 20;
				inputStyle.padding = new RectOffset(10, 10, 7, 6);
				inputStyle.normal.textColor = Color.white;
				inputStyle.focused.textColor = Color.white;
				suggestionStyle = new GUIStyle(GUI.skin.button);
				suggestionStyle.alignment = (TextAnchor)3;
				suggestionStyle.fontSize = 15;
				suggestionStyle.normal.textColor = new Color(0.86f, 0.9f, 0.91f);
				selectedSuggestionStyle = new GUIStyle(suggestionStyle);
				selectedSuggestionStyle.normal.background = selectedBackground;
				selectedSuggestionStyle.normal.textColor = new Color(0.35f, 1f, 0.56f);
				selectedSuggestionStyle.fontStyle = (FontStyle)1;
				resultStyle = new GUIStyle(GUI.skin.box);
				resultStyle.alignment = (TextAnchor)0;
				resultStyle.fontSize = 14;
				resultStyle.wordWrap = true;
				resultStyle.padding = new RectOffset(10, 10, 8, 8);
				resultStyle.normal.textColor = Color.white;
			}
		}

		private static Texture2D MakeTexture(Color color)
		{
			//IL_0004: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}

		public void Dispose()
		{
			Network.Dispose();
			Permissions.Reset();
			if ((Object)(object)windowBackground != (Object)null)
			{
				Object.Destroy((Object)(object)windowBackground);
			}
			if ((Object)(object)selectedBackground != (Object)null)
			{
				Object.Destroy((Object)(object)selectedBackground);
			}
		}
	}
	[BepInPlugin("com.jameskieley.repo.commandconsole", "REPO Command Console", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "com.jameskieley.repo.commandconsole";

		internal const string PluginName = "REPO Command Console";

		internal const string PluginVersion = "2.0.0";

		private CommandConsoleRuntime commandConsole;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal CommandConsoleRuntime CommandConsole => commandConsole;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			commandConsole = new CommandConsoleRuntime(this);
			Bridge.PublishPermissionSessionRevision(commandConsole.Permissions.SessionRevision);
			Bridge.Start();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("REPO Command Console 2.0.0 loaded. Press " + commandConsole.ToggleKeyLabel + " to open the command console."));
		}

		private void Update()
		{
			if (commandConsole != null)
			{
				commandConsole.Update();
			}
		}

		private void OnGUI()
		{
			if (commandConsole != null)
			{
				commandConsole.OnGUI();
			}
		}

		private void OnDestroy()
		{
			if (commandConsole != null)
			{
				commandConsole.Dispose();
			}
			commandConsole = null;
			Instance = null;
		}
	}
	public static class Loader
	{
		public static void Load()
		{
			Bridge.Start();
		}
	}
	internal sealed class ControlRequest
	{
		internal readonly string Command;

		internal readonly CommandRequestSource Source;

		internal readonly int RequesterActorNumber;

		internal readonly Action<string> CompletionCallback;

		internal readonly long? RequiredSessionRevision;

		internal readonly Func<bool> AuthorizationValidator;

		internal readonly ManualResetEventSlim Completed = new ManualResetEventSlim(initialState: false);

		internal string Result = "ERROR No result was produced.";

		internal bool ExecutionContextBound;

		internal bool ExecutionStartedInRoom;

		internal object ExecutionRoomIdentity;

		internal int ExecutionMasterActorNumber = -1;

		internal long ExecutionSessionRevision = -1L;

		private int completionState;

		private int cancellationState;

		internal bool IsCancelled => Volatile.Read(in cancellationState) != 0;

		internal ControlRequest(string command)
			: this(command, CommandRequestSource.NamedPipe, -1, null, CapturePublishedSessionRevision(), null)
		{
		}

		internal ControlRequest(string command, CommandRequestSource source, int requesterActorNumber, Action<string> completionCallback)
			: this(command, source, requesterActorNumber, completionCallback, null, null)
		{
		}

		internal ControlRequest(string command, CommandRequestSource source, int requesterActorNumber, Action<string> completionCallback, long? requiredSessionRevision, Func<bool> authorizationValidator)
		{
			Command = command;
			Source = source;
			RequesterActorNumber = requesterActorNumber;
			CompletionCallback = completionCallback;
			RequiredSessionRevision = requiredSessionRevision;
			AuthorizationValidator = authorizationValidator;
		}

		internal void Complete(string result)
		{
			if (Interlocked.Exchange(ref completionState, 1) != 0)
			{
				return;
			}
			Result = result;
			Completed.Set();
			if (CompletionCallback == null)
			{
				return;
			}
			try
			{
				CompletionCallback(result);
			}
			catch (Exception ex)
			{
				if (Plugin.Log != null)
				{
					Plugin.Log.LogError((object)("Command completion callback failed: " + ex));
				}
			}
		}

		internal void Cancel(string result)
		{
			Interlocked.Exchange(ref cancellationState, 1);
			if (Interlocked.Exchange(ref completionState, 1) == 0)
			{
				Result = result;
				Completed.Set();
			}
		}

		private static long? CapturePublishedSessionRevision()
		{
			long publishedPermissionSessionRevision = Bridge.GetPublishedPermissionSessionRevision();
			if (publishedPermissionSessionRevision < 0)
			{
				return null;
			}
			return publishedPermissionSessionRevision;
		}
	}
	internal enum CommandRequestSource
	{
		NamedPipe,
		LocalConsole,
		RemoteClient
	}
	internal enum SpawnKind
	{
		Enemy,
		Loot,
		Item,
		Cart
	}
	internal sealed class EnemyPlacementReservation
	{
		internal readonly Vector3 Position;

		internal readonly float HorizontalRadius;

		internal EnemyPlacementReservation(Vector3 position, float horizontalRadius)
		{
			//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)
			Position = position;
			HorizontalRadius = horizontalRadius;
		}
	}
	internal sealed class EnemyClearanceVolume
	{
		internal readonly Vector3 CenterOffset;

		internal readonly Vector3 HalfExtents;

		internal readonly float HorizontalRadius;

		internal EnemyClearanceVolume(Vector3 centerOffset, Vector3 halfExtents, float horizontalRadius)
		{
			//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_000e: 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)
			CenterOffset = centerOffset;
			HalfExtents = halfExtents;
			HorizontalRadius = horizontalRadius;
		}
	}
	internal sealed class SpawnJob
	{
		internal readonly ControlRequest Request;

		internal readonly SpawnKind Kind;

		internal readonly string Selector;

		internal readonly string Placement;

		internal readonly int Requested;

		internal readonly Vector3 Anchor;

		internal readonly List<Vector3> ReservedPositions = new List<Vector3>();

		internal readonly List<EnemyPlacementReservation> EnemyReservations = new List<EnemyPlacementReservation>();

		internal int Spawned;

		internal bool Finished;

		internal readonly SpawnNameSummary NameSummary = new SpawnNameSummary();

		internal SpawnJob(ControlRequest request, SpawnKind kind, string selector, string placement, int requested, Vector3 anchor)
		{
			//IL_004d: 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)
			Request = request;
			Kind = kind;
			Selector = selector;
			Placement = placement;
			Requested = requested;
			Anchor = anchor;
		}
	}
	internal sealed class SpawnedObjectRecord
	{
		internal GameObject Instance;

		internal string Name;

		internal SpawnKind Kind;

		internal bool IsWeapon;
	}
	internal sealed class DuplicateLootJob
	{
		internal readonly ControlRequest Request;

		internal readonly List<PrefabRef> Prefabs;

		internal readonly Vector3 Anchor;

		internal readonly List<Vector3> Positions = new List<Vector3>();

		internal int Spawned;

		internal bool Finished;

		internal DuplicateLootJob(ControlRequest request, List<PrefabRef> prefabs, Vector3 anchor)
		{
			//IL_0020: 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)
			Request = request;
			Prefabs = prefabs;
			Anchor = anchor;
		}
	}
	internal sealed class ItemBatchJob
	{
		internal readonly ControlRequest Request;

		internal readonly List<Item> Items;

		internal readonly List<string> TypeNames;

		internal readonly string Placement;

		internal readonly int CountPerType;

		internal readonly Vector3 Anchor;

		internal readonly List<Vector3> ReservedPositions = new List<Vector3>();

		internal int Spawned;

		internal bool Finished;

		internal ItemBatchJob(ControlRequest request, List<Item> items, List<string> typeNames, string placement, int countPerType, Vector3 anchor)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Request = request;
			Items = items;
			TypeNames = typeNames;
			Placement = placement;
			CountPerType = countPerType;
			Anchor = anchor;
		}
	}
	internal sealed class BalancedItemJob
	{
		internal readonly ControlRequest Request;

		internal readonly List<Item> Items;

		internal readonly List<string> TypeNames;

		internal readonly Dictionary<string, int> TypeCounts;

		internal readonly string Placement;

		internal readonly Vector3 Anchor;

		internal readonly List<Vector3> ReservedPositions = new List<Vector3>();

		internal int Spawned;

		internal bool Finished;

		internal BalancedItemJob(ControlRequest request, List<Item> items, List<string> typeNames, Dictionary<string, int> typeCounts, string placement, Vector3 anchor)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Request = request;
			Items = items;
			TypeNames = typeNames;
			TypeCounts = typeCounts;
			Placement = placement;
			Anchor = anchor;
		}
	}
	internal static class Bridge
	{
		internal const string PipeName = "CodexRepoCommandConsoleV2";

		private const string HarmonyId = "com.jameskieley.repo.commandconsole.harmony";

		private static readonly ConcurrentQueue<ControlRequest> Requests = new ConcurrentQueue<ControlRequest>();

		private static readonly List<SpawnedObjectRecord> SpawnedObjects = new List<SpawnedObjectRecord>();

		private static readonly FieldInfo EnemyFirstSpawnPointField = AccessTools.Field(typeof(EnemyParent), "firstSpawnPoint");

		private static readonly FieldInfo EnemyFirstSpawnPointsField = AccessTools.Field(typeof(EnemyDirector), "enemyFirstSpawnPoints");

		private static readonly string[] ExpensiveLootNames = new string[5] { "Diamond Display", "Griffin Statue", "Dragon Skull", "GoldTooth", "Server Rack" };

		private static readonly string[] WeaponTerms = new string[28]
		{
			"weapon", "melee", "ranged", "gun", "pistol", "rifle", "shotgun", "revolver", "blaster", "cannon",
			"launcher", "sword", "blade", "knife", "dagger", "axe", "hatchet", "bat", "hammer", "mace",
			"spear", "bow", "crossbow", "grenade", "mine", "bomb", "pan", "taser"
		};

		private static int started;

		private static long publishedPermissionSessionRevision = -1L;

		private static SpawnJob activeJob;

		private static DuplicateLootJob activeDuplicateLootJob;

		private static ItemBatchJob activeItemBatchJob;

		private static BalancedItemJob activeBalancedItemJob;

		internal static void Start()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (Interlocked.Exchange(ref started, 1) == 0)
			{
				Harmony.UnpatchID("Codex.REPO.SpawnBridge");
				Harmony.UnpatchID("Codex.REPO.SpawnBridge.V2");
				Harmony.UnpatchID("Codex.REPO.ControlBridge");
				Harmony.UnpatchID("Codex.REPO.LiveControl");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V2");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V3");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V4");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V5");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V6");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V7");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V8");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V9");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V10");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V11");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V12");
				Harmony.UnpatchID("Codex.REPO.LiveControl.V13");
				Harmony.UnpatchID("com.jameskieley.repo.commandconsole.harmony");
				new Harmony("com.jameskieley.repo.commandconsole.harmony").PatchAll(typeof(Bridge).Assembly);
				Thread thread = new Thread(ListenForRequests);
				thread.IsBackground = true;
				thread.Name = "Codex REPO Live Control";
				thread.Start();
			}
		}

		internal static void Enqueue(ControlRequest request)
		{
			if (request == null)
			{
				throw new ArgumentNullException("request");
			}
			Requests.Enqueue(request);
		}

		internal static void PublishPermissionSessionRevision(long revision)
		{
			Interlocked.Exchange(ref publishedPermissionSessionRevision, revision);
		}

		internal static long GetPublishedPermissionSessionRevision()
		{
			return Interlocked.Read(in publishedPermissionSessionRevision);
		}

		private static void ListenForRequests()
		{
			while (true)
			{
				try
				{
					using NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream("CodexRepoCommandConsoleV2", PipeDirection.InOut, 1);
					namedPipeServerStream.WaitForConnection();
					string text;
					using (StreamReader streamReader = new StreamReader(namedPipeServerStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), detectEncodingFromByteOrderMarks: false, 1024, leaveOpen: true))
					{
						text = streamReader.ReadLine();
					}
					string text2;
					if (string.IsNullOrWhiteSpace(text))
					{
						text2 = "ERROR Empty command.";
					}
					else
					{
						ControlRequest controlRequest = new ControlRequest(text);
						Requests.Enqueue(controlRequest);
						if (controlRequest.Completed.Wait(TimeSpan.FromSeconds(30.0)))
						{
							text2 = controlRequest.Result;
						}
						else
						{
							text2 = "ERROR Command timed out waiting for the game thread; the queued request was cancelled.";
							controlRequest.Cancel(text2);
						}
					}
					using StreamWriter streamWriter = new StreamWriter(namedPipeServerStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 1024, leaveOpen: true);
					streamWriter.AutoFlush = true;
					streamWriter.WriteLine(text2);
				}
				catch (Exception ex)
				{
					try
					{
						File.AppendAllText(Path.Combine(Path.GetTempPath(), "RepoLiveControl-pipe.log"), DateTime.UtcNow.ToString("O") + " " + ex?.ToString() + Environment.NewLine);
					}
					catch
					{
					}
					Thread.Sleep(250);
				}
			}
		}

		internal static void ProcessFrame()
		{
			if (HasActiveJob())
			{
				RefreshPermissionSession();
				if (AbortActiveJobsIfAuthorityLost())
				{
					return;
				}
			}
			if (activeBalancedItemJob != null)
			{
				ProcessBalancedItemJob(activeBalancedItemJob);
				if (activeBalancedItemJob.Finished)
				{
					activeBalancedItemJob = null;
				}
			}
			else if (activeItemBatchJob != null)
			{
				ProcessItemBatchJob(activeItemBatchJob);
				if (activeItemBatchJob.Finished)
				{
					activeItemBatchJob = null;
				}
			}
			else if (activeDuplicateLootJob != null)
			{
				ProcessDuplicateLootJob(activeDuplicateLootJob);
				if (activeDuplicateLootJob.Finished)
				{
					activeDuplicateLootJob = null;
				}
			}
			else if (activeJob != null)
			{
				ProcessSpawnJob(activeJob);
				if (activeJob.Finished)
				{
					activeJob = null;
				}
			}
			else
			{
				if (!Requests.TryDequeue(out var result) || result.IsCancelled)
				{
					return;
				}
				try
				{
					RefreshPermissionSession();
					BindExecutionContext(result);
					string invalidExecutionReason = GetInvalidExecutionReason(result);
					if (invalidExecutionReason != null)
					{
						throw new InvalidOperationException(invalidExecutionReason);
					}
					Dispatch(result);
				}
				catch (Exception ex)
				{
					Complete(result, "ERROR " + ex.Message);
				}
			}
		}

		private static bool AbortActiveJobsIfAuthorityLost()
		{
			bool result = false;
			if (activeBalancedItemJob != null)
			{
				string invalidExecutionReason = GetInvalidExecutionReason(activeBalancedItemJob.Request);
				if (!activeBalancedItemJob.Finished && invalidExecutionReason != null)
				{
					activeBalancedItemJob.Finished = true;
					activeBalancedItemJob.ReservedPositions.Clear();
					Complete(activeBalancedItemJob.Request, string.Format("ERROR {2} Balanced item spread stopped after {0}/{1}.", activeBalancedItemJob.Spawned, activeBalancedItemJob.Items.Count, invalidExecutionReason));
					result = true;
				}
				if (activeBalancedItemJob.Finished)
				{
					activeBalancedItemJob = null;
				}
			}
			if (activeItemBatchJob != null)
			{
				string invalidExecutionReason2 = GetInvalidExecutionReason(activeItemBatchJob.Request);
				if (!activeItemBatchJob.Finished && invalidExecutionReason2 != null)
				{
					activeItemBatchJob.Finished = true;
					activeItemBatchJob.ReservedPositions.Clear();
					Complete(activeItemBatchJob.Request, string.Format("ERROR {2} Item batch stopped after {0}/{1}.", activeItemBatchJob.Spawned, activeItemBatchJob.Items.Count, invalidExecutionReason2));
					result = true;
				}
				if (activeItemBatchJob.Finished)
				{
					activeItemBatchJob = null;
				}
			}
			if (activeDuplicateLootJob != null)
			{
				string invalidExecutionReason3 = GetInvalidExecutionReason(activeDuplicateLootJob.Request);
				if (!activeDuplicateLootJob.Finished && invalidExecutionReason3 != null)
				{
					activeDuplicateLootJob.Finished = true;
					activeDuplicateLootJob.Positions.Clear();
					Complete(activeDuplicateLootJob.Request, string.Format("ERROR {2} Loot duplication stopped after {0}/{1}.", activeDuplicateLootJob.Spawned, activeDuplicateLootJob.Prefabs.Count, invalidExecutionReason3));
					result = true;
				}
				if (activeDuplicateLootJob.Finished)
				{
					activeDuplicateLootJob = null;
				}
			}
			if (activeJob != null)
			{
				string invalidExecutionReason4 = GetInvalidExecutionReason(activeJob.Request);
				if (!activeJob.Finished && invalidExecutionReason4 != null)
				{
					activeJob.Finished = true;
					activeJob.ReservedPositions.Clear();
					activeJob.EnemyReservations.Clear();
					Complete(activeJob.Request, string.Format("ERROR {2} Spawn stopped after {0}/{1}.", activeJob.Spawned, activeJob.Requested, invalidExecutionReason4));
					result = true;
				}
				if (activeJob.Finished)
				{
					activeJob = null;
				}
			}
			return result;
		}

		private static void RefreshPermissionSession()
		{
			PermissionService permissionService = GetPermissionService();
			if (permissionService != null)
			{
				permissionService.UpdateSession();
				PublishPermissionSessionRevision(permissionService.SessionRevision);
			}
		}

		private static bool HasActiveJob()
		{
			if (activeBalancedItemJob == null && activeItemBatchJob == null && activeDuplicateLootJob == null)
			{
				return activeJob != null;
			}
			return true;
		}

		private static PermissionService GetPermissionService()
		{
			if (!((Object)(object)Plugin.Instance != (Object)null) || Plugin.Instance.CommandConsole == null)
			{
				return null;
			}
			return Plugin.Instance.CommandConsole.Permissions;
		}

		private static void BindExecutionContext(ControlRequest request)
		{
			if (!request.ExecutionContextBound)
			{
				PermissionService permissionService = GetPermissionService();
				request.ExecutionStartedInRoom = PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null;
				request.ExecutionRoomIdentity = PhotonNetwork.CurrentRoom;
				request.ExecutionMasterActorNumber = ((PhotonNetwork.MasterClient == null) ? (-1) : PhotonNetwork.MasterClient.ActorNumber);
				request.ExecutionSessionRevision = permissionService?.SessionRevision ?? (-1);
				request.ExecutionContextBound = true;
			}
		}

		private static string GetInvalidExecutionReason(ControlRequest request)
		{
			if (request == null || !request.ExecutionContextBound)
			{
				return "The command has no valid execution session.";
			}
			PermissionService permissionService = GetPermissionService();
			string text = CommandIngressSessionPolicy.Validate(request.IsCancelled, request.RequiredSessionRevision, permissionService?.SessionRevision);
			if (text != null)
			{
				return text;
			}
			if (request.AuthorizationValidator != null)
			{
				bool flag;
				try
				{
					flag = request.AuthorizationValidator();
				}
				catch
				{
					flag = false;
				}
				if (!flag)
				{
					return "The requester is no longer authorized in this lobby.";
				}
			}
			if (request.ExecutionStartedInRoom)
			{
				if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
				{
					return "The original multiplayer room closed.";
				}
				if (request.ExecutionRoomIdentity != PhotonNetwork.CurrentRoom)
				{
					return "The multiplayer room changed.";
				}
				if (!PhotonNetwork.IsMasterClient)
				{
					return "Host authority was lost.";
				}
				if (((PhotonNetwork.MasterClient == null) ? (-1) : PhotonNetwork.MasterClient.ActorNumber) != request.ExecutionMasterActorNumber)
				{
					return "The lobby host changed.";
				}
				if (permissionService != null && request.ExecutionSessionRevision != permissionService.SessionRevision)
				{
					return "The multiplayer session changed.";
				}
			}
			else
			{
				if (request.Source == CommandRequestSource.RemoteClient)
				{
					return "Remote commands require their original multiplayer room.";
				}
				if (PhotonNetwork.InRoom)
				{
					return "The multiplayer session changed after the command began.";
				}
			}
			return null;
		}

		private static void Dispatch(ControlRequest request)
		{
			string translatedCommand = request.Command;
			if (!translatedCommand.StartsWith("/", StringComparison.Ordinal) || SlashCommandRuntime.TryTranslateOrComplete(request, translatedCommand, out translatedCommand))
			{
				string[] parts = translatedCommand.Split('|');
				string text = Part(parts, 0, string.Empty).ToLowerInvariant();
				switch (text)
				{
				case "enemy":
					BeginSpawn(request, SpawnKind.Enemy, parts, 500, "near-player");
					break;
				case "loot":
					BeginSpawn(request, SpawnKind.Loot, parts, 500, "safe");
					break;
				case "item":
					BeginSpawn(request, SpawnKind.Item, parts, 500, "safe");
					break;
				case "cart":
					BeginSpawn(request, SpawnKind.Cart, parts, 20, "at-player");
					break;
				case "itemeach":
					BeginItemEach(request, parts);
					break;
				case "itemspread":
					BeginBalancedItems(request, parts);
					break;
				case "despawn":
					DespawnEnemies(request, Part(parts, 1, "all"), ParseInt(parts, 2, 0));
					break;
				case "despawnitem":
					DespawnItems(request, Part(parts, 1, "all"));
					break;
				case "despawnspawned":
					DespawnSpawnedObjects(request, Part(parts, 1, "all"), Part(parts, 2, "all"), ParseInt(parts, 3, -1));
					break;
				case "auto":
					SetAutomaticEnemies(request, Part(parts, 1, "on"));
					break;
				case "unstick":
					UnstickLoot(request);
					break;
				case "duplicate":
					DuplicateLoot(request, Part(parts, 1, "loot"));
					break;
				case "topup3":
					TopUpLootAfterOneDuplicate(request, Part(parts, 1, "loot"));
					break;
				case "inspect":
					InspectLoot(request, Part(parts, 1, "loot"));
					break;
				case "status":
					ReportStatus(request);
					break;
				default:
					throw new InvalidOperationException("Unknown action '" + text + "'.");
				}
			}
		}

		private static void BeginItemEach(ControlRequest request, string[] parts)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			string text = Part(parts, 1, "upgrade");
			int num = Mathf.Clamp(ParseInt(parts, 2, 1), 1, 50);
			string placement = Part(parts, 3, "safe").ToLowerInvariant();
			PlayerAvatar val = RequireRequestPlayer(request);
			List<Item> list = new List<Item>();
			List<string> list2 = new List<string>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (Item allItem in Items.AllItems)
			{
				if (!((Object)(object)allItem == (Object)null) && !string.IsNullOrWhiteSpace(allItem.itemName) && allItem.itemName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 && hashSet.Add(allItem.itemName))
				{
					list2.Add(allItem.itemName);
					for (int i = 0; i < num; i++)
					{
						list.Add(allItem);
					}
				}
			}
			if (list.Count == 0)
			{
				throw new InvalidOperationException("No item types match '" + text + "'.");
			}
			activeItemBatchJob = new ItemBatchJob(request, list, list2, placement, num, ((Component)val).transform.position);
			ProcessItemBatchJob(activeItemBatchJob);
		}

		private static void BeginBalancedItems(ControlRequest request, string[] parts)
		{
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			string text = Part(parts, 1, "upgrade");
			int num = Mathf.Clamp(ParseInt(parts, 2, 1), 1, 500);
			string placement = Part(parts, 3, "safe").ToLowerInvariant();
			PlayerAvatar val = RequireRequestPlayer(request);
			List<Item> list = new List<Item>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			bool flag = text.Equals("weapon", StringComparison.OrdinalIgnoreCase) || text.Equals("weapons", StringComparison.OrdinalIgnoreCase);
			foreach (Item allItem in Items.AllItems)
			{
				if (!((Object)(object)allItem == (Object)null) && !string.IsNullOrWhiteSpace(allItem.itemName) && (flag ? IsWeaponItem(allItem) : (allItem.itemName.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0)) && hashSet.Add(allItem.itemName))
				{
					list.Add(allItem);
				}
			}
			if (list.Count == 0)
			{
				throw new InvalidOperationException("No item types match '" + text + "'.");
			}
			Shuffle(list);
			List<Item> list2 = new List<Item>(num);
			List<string> list3 = new List<string>();
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < num; i++)
			{
				Item val2 = list[i % list.Count];
				list2.Add(val2);
				if (!dictionary.ContainsKey(val2.itemName))
				{
					list3.Add(val2.itemName);
				}
				dictionary[val2.itemName] = ((!dictionary.ContainsKey(val2.itemName)) ? 1 : (dictionary[val2.itemName] + 1));
			}
			activeBalancedItemJob = new BalancedItemJob(request, list2, list3, dictionary, placement, ((Component)val).transform.position);
			ProcessBalancedItemJob(activeBalancedItemJob);
		}

		private static void ProcessItemBatchJob(ItemBatchJob job)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = 0;
				while (!job.Finished && num < 10)
				{
					Item val = job.Items[job.Spawned];
					Vector3 placement = GetPlacement(job.Placement, job.Anchor, job.ReservedPositions);
					GameObject val2 = Items.SpawnItem(val, placement, Quaternion.identity);
					if ((Object)(object)val2 == (Object)null)
					{
						throw new InvalidOperationException("REPOLib returned no spawned item object for '" + val.itemName + "'.");
					}
					SpawnedObjects.Add(new SpawnedObjectRecord
					{
						Instance = val2,
						Name = val.itemName,
						Kind = SpawnKind.Item,
						IsWeapon = IsWeaponItem(val)
					});
					job.Spawned++;
					num++;
					if (job.Spawned >= job.Items.Count)
					{
						job.Finished = true;
						Complete(job.Request, string.Format("OK Spawned {0} item object(s): {1} each of {2} matching type(s): {3}.", job.Spawned, job.CountPerType, job.TypeNames.Count, string.Join(", ", job.TypeNames.ToArray())));
					}
				}
			}
			catch (Exception ex)
			{
				job.Finished = true;
				Complete(job.Request, $"ERROR Item batch stopped after {job.Spawned}/{job.Items.Count}: {ex.Message}");
			}
		}

		private static void ProcessBalancedItemJob(BalancedItemJob job)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int num = 0;
				while (!job.Finished && num < 10)
				{
					Item val = job.Items[job.Spawned];
					Vector3 placement = GetPlacement(job.Placement, job.Anchor, job.ReservedPositions);
					GameObject val2 = Items.SpawnItem(val, placement, Quaternion.identity);
					if ((Object)(object)val2 == (Object)null)
					{
						throw new InvalidOperationException("REPOLib returned no spawned item object for '" + val.itemName + "'.");
					}
					SpawnedObjects.Add(new SpawnedObjectRecord
					{
						Instance = val2,
						Name = val.itemName,
						Kind = SpawnKind.Item,
						IsWeapon = IsWeaponItem(val)
					});
					job.Spawned++;
					num++;
					if (job.Spawned < job.Items.Count)
					{
						continue;
					}
					job.Finished = true;
					List<string> list = new List<string>();
					foreach (string typeName in job.TypeNames)
					{
						list.Add(typeName + " x" + job.TypeCounts[typeName]);
					}
					Complete(job.Request, string.Format("OK Spawned {0} balanced item object(s) across {1} type(s): {2}.", job.Spawned, job.TypeNames.Count, string.Join(", ", list.ToArray())));
				}
			}
			catch (Exception ex)
			{
				job.Finished = true;
				Complete(job.Request, $"ERROR Balanced item spread stopped after {job.Spawned}/{job.Items.Count}: {ex.Message}");
			}
		}

		private static void InspectLoot(ControlRequest request, string target)
		{
			if (!target.Equals("loot", StringComparison.OrdinalIgnoreCase))
			{
				throw new InvalidOperationException("Inspect target must be loot.");
			}
			IList obj = (GetField(ValuableDirector.instance, "valuableList") as IList) ?? throw new InvalidOperationException("The tracked loot list is unavailable.");
			List<string> list = new List<string>();
			foreach (object item in obj)
			{
				ValuableObject val = (ValuableObject)((item is ValuableObject) ? item : null);
				if ((Object)(object)val != (Object)null && !list.Contains(((Object)((Component)val).gameObject).name))
				{
					list.Add(((Object)((Component)val).gameObject).name);
				}
			}
			List<string> list2 = new List<string>();
			foreach (PrefabRef allValuable in Valuables.AllValuables)
			{
				if ((Object)(object)((PrefabRef<GameObject>)(object)allValuable).Prefab != (Object)null)
				{
					list2.Add(((Object)((PrefabRef<GameObject>)(object)allValuable).Prefab).name);
				}
			}
			Complete(request, "OK Loot inspection: tracked=[" + string.Join(", ", list.ToArray()) + "]; registered=[" + string.Join(", ", list2.ToArray()) + "].");
		}

		private static void DuplicateLoot(ControlRequest request, string target)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (!target.Equals("loot", StringComparison.OrdinalIgnoreCase))
			{
				throw new InvalidOperationException("Duplicate target must be loot.");
			}
			IList obj = (GetField(ValuableDirector.instance, "valuableList") as IList) ?? throw new InvalidOperationException("The tracked loot list is unavailable.");
			List<PrefabRef> list = new List<PrefabRef>();
			foreach (object item in obj)
			{
				ValuableObject val = (ValuableObject)((item is ValuableObject) ? item : null);
				if (!((Object)(object)val == (Object)null))
				{
					PrefabRef val2 = FindValuablePrefab(val);
					if (val2 == null)
					{
						throw new InvalidOperationException("No registered valuable prefab matches existing loot '" + ((Object)((Component)val).gameObject).name + "'. No copies were spawned.");
					}
					list.Add(val2);
				}
			}
			if (list.Count == 0)
			{
				Complete(request, "OK Duplicated 0 loot object(s); the map had no tracked loot.");
				return;
			}
			PlayerAvatar val3 = RequireRequestPlayer(request);
			Shuffle(list);
			activeDuplicateLootJob = new DuplicateLootJob(request, list, ((Component)val3).transform.position);
			ProcessDuplicateLootJob(activeDuplicateLootJob);
		}

		private static void TopUpLootAfterOneDuplicate(ControlRequest request, string target)
		{
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			if (!target.Equals("loot", StringComparison.OrdinalIgnoreCase))
			{
				throw new InvalidOperationException("Top-up target must be loot.");
			}
			IList obj = (GetField(ValuableDirector.instance, "valuableList") as IList) ?? throw new InvalidOperationException("The tracked loot list is unavailable.");
			List<PrefabRef> list = new List<PrefabRef>();
			List<int> list2 = new List<int>();
			foreach (object item in obj)
			{
				ValuableObject val = (ValuableObject)((item is ValuableObject) ? item : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				PrefabRef val2 = FindValuablePrefab(val);
				if (val2 == null)
				{
					throw new InvalidOperationException("No registered valuable prefab matches existing loot '" + ((Object)((Component)val).gameObject).name + "'. No copies were spawned.");
				}
				int num = -1;
				for (int i = 0; i < list.Count; i++)
				{
					if (list[i] == val2)
					{
						num = i;
						break;
					}
				}
				if (num < 0)
				{
					list.Add(val2);
					list2.Add(1);
				}
				else
				{
					list2[num]++;
				}
			}
			List<PrefabRef> list3 = new List<PrefabRef>();
			for (int j = 0; j < list.Count; j++)
			{
				int num2 = list2[j] / 2;
				for (int k = 0; k < num2; k++)
				{
					list3.Add(list[j]);
				}
			}
			if (list3.Count == 0)
			{
				Complete(request, "OK Added 0 loot object(s); no complete duplicated pairs were found.");
				return;
			}
			PlayerAvatar val3 = RequireRequestPlayer(request);
			Shuffle(list3);
			activeDuplicateLootJob = new DuplicateLootJob(request, list3, ((Component)val3).transform.position);
			ProcessDuplicateLootJob(activeDuplicateLootJob);
		}

		private static void ProcessDuplicateLootJob(DuplicateLootJob job)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			try
			{
				int num = 0;
				while (!job.Finished && num < 10)
				{
					if (job.Positions.Count < job.Prefabs.Count)
					{
						if (!TryFindClearPosition(job.Anchor, job.Positions, out var result))
						{
							throw new InvalidOperationException("Could not reserve collision-free locations for all copies. No copies were spawned.");
						}
						job.Positions.Add(result);
					}
					else
					{
						PrefabRef val = job.Prefabs[job.Spawned];
						GameObject val2 = Valuables.SpawnValuable(val, job.Positions[job.Spawned], Quaternion.identity);
						if ((Object)(object)val2 == (Object)null)
						{
							throw new InvalidOperationException("REPOLib returned no spawned loot object for '" + ((Object)((PrefabRef<GameObject>)(object)val).Prefab).name + "'.");
						}
						SpawnedObjects.Add(new SpawnedObjectRecord
						{
							Instance = val2,
							Name = ((Object)((PrefabRef<GameObject>)(object)val).Prefab).name,
							Kind = SpawnKind.Loot,
							IsWeapon = false
						});
						job.Spawned++;
						if (job.Spawned >= job.Prefabs.Count)
						{
							job.Finished = true;
							Complete(job.Request, $"OK Duplicated {job.Spawned} loot object(s) into distinct collision-free random locations.");
						}
					}
					num++;
				}
			}
			catch (Exception ex)
			{
				job.Finished = true;
				Complete(job.Request, $"ERROR Loot duplication stopped after {job.Spawned}/{job.Prefabs.Count}: {ex.Message}");
			}
		}

		private static void BeginSpawn(ControlRequest request, SpawnKind kind, string[] parts, int maximum, string defaultPlacement)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar val = RequireRequestPlayer(request);
			string selector = Part(parts, 1, "random");
			int requested = Mathf.Clamp(ParseInt(parts, 2, 1), 1, maximum);
			string placement = Part(parts, 3, defaultPlacement).ToLowerInvariant();
			activeJob = new SpawnJob(request, kind, selector, placement, requested, ((Component)val).transform.position);
			ProcessSpawnJob(activeJob);
		}

		private static void ProcessSpawnJob(SpawnJob job)
		{
			try
			{
				int num = 0;
				while (!job.Finished && num < 10)
				{
					switch (job.Kind)
					{
					case SpawnKind.Enemy:
						SpawnEnemyStep(job);
						break;
					case SpawnKind.Loot:
						SpawnLootStep(job);
						break;
					case SpawnKind.Item:
						SpawnItemStep(job);
						break;
					case SpawnKind.Cart:
						SpawnCartStep(job);
						break;
					}
					num++;
					if (job.Spawned >= job.Requested)
					{
						job.Finished = true;
						string text = job.NameSummary.Format();
						string result = string.Format("OK Spawned {0} {1} object(s){2}.", job.Spawned, job.Kind.ToString().ToLowerInvariant(), (text.Length == 0) ? string.Empty : (": " + text));
						Complete(job.Request, result);
					}
				}
			}
			catch (Exception ex)
			{
				job.Finished = true;
				Complete(job.Request, $"ERROR Spawn stopped after {job.Spawned}/{job.Requested}: {ex.Message}");
			}
		}

		private static void SpawnEnemyStep(SpawnJob job)
		{
			//IL_0043: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			EnemySetup val = FindEnemy(job.Selector);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("No enemy matches '" + job.Selector + "'.");
			}
			Vector3 result;
			if (job.Placement == "safe")
			{
				if (!TryFindClearEnemyPosition(job.Anchor, job.EnemyReservations, GetEnemyClearanceVolume(val), out result))
				{
					throw new InvalidOperationException("No additional collision-free enemy placement was found.");
				}
			}
			else if (job.Placement == "at-player")
			{
				result = SemiFunc.EnemyRoamFindPoint(job.Anchor);
			}
			else
			{
				Vector3 val2 = Random.insideUnitSphere * 4f;
				val2.y = 0f;
				result = SemiFunc.EnemyRoamFindPoint(job.Anchor + val2);
			}
			List<EnemyParent> list = Enemies.SpawnEnemy(val, result, Quaternion.identity, false);
			if (list == null || list.Count == 0)
			{
				throw new InvalidOperationException("The enemy setup spawned no objects.");
			}
			List<EnemyParent> list2 = new List<EnemyParent>();
			foreach (EnemyParent item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					list2.Add(item);
				}
			}
			if (list2.Count == 0)
			{
				throw new InvalidOperationException("The enemy setup returned no live objects.");
			}
			int num = CommandExecutionTranslation.AcceptedEnemyCountForSetup(job.Requested - job.Spawned, list2.Count, job.Placement == "safe");
			EnemyDirector instance = EnemyDirector.instance;
			for (int i = num; i < list2.Count; i++)
			{
				DestroyEnemyInstance(list2[i], instance);
			}
			EnemyParent enemyParent = GetEnemyParent(val);
			string name = (((Object)(object)enemyParent == (Object)null) ? "unknown" : enemyParent.enemyName);
			for (int j = 0; j < num; j++)
			{
				EnemyParent val3 = list2[j];
				SpawnedObjects.Add(new SpawnedObjectRecord
				{
					Instance = ((Component)val3).gameObject,
					Name = name,
					Kind = SpawnKind.Enemy,
					IsWeapon = false
				});
			}
			AppendName(job, name, num);
			job.Spawned += num;
		}

		private static void DestroyEnemyInstance(EnemyParent enemy, EnemyDirector director)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemy == (Object)null)
			{
				return;
			}
			if ((Object)(object)director != (Object)null)
			{
				director.enemiesSpawned.Remove(enemy);
				LevelPoint val = ((EnemyFirstSpawnPointField == null) ? ((LevelPoint)null) : ((LevelPoint)EnemyFirstSpawnPointField.GetValue(enemy)));
				List<LevelPoint> list = ((EnemyFirstSpawnPointsField == null) ? null : ((List<LevelPoint>)EnemyFirstSpawnPointsField.GetValue(director)));
				if ((Object)(object)val != (Object)null)
				{
					list?.Remove(val);
				}
			}
			if (PhotonNetwork.InRoom)
			{
				PhotonNetwork.Destroy(((Component)enemy).gameObject);
			}
			else
			{
				Object.Destroy((Object)(object)((Component)enemy).gameObject);
			}
		}

		private static void SpawnLootStep(SpawnJob job)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			PrefabRef val = FindValuable(job.Selector, job.Spawned);
			if (val == null)
			{
				throw new InvalidOperationException("No loot matches '" + job.Selector + "'.");
			}
			Vector3 placement = GetPlacement(job);
			GameObject val2 = Valuables.SpawnValuable(val, placement, Quaternion.identity);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("REPOLib returned no spawned loot object.");
			}
			SpawnedObjects.Add(new SpawnedObjectRecord
			{
				Instance = val2,
				Name = ((Object)((PrefabRef<GameObject>)(object)val).Prefab).name,
				Kind = SpawnKind.Loot,
				IsWeapon = false
			});
			AppendName(job, ((Object)((PrefabRef<GameObject>)(object)val).Prefab).name, 1);
			job.Spawned++;
		}

		private static void SpawnItemStep(SpawnJob job)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Item val = FindItem(job.Selector);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("No item matches '" + job.Selector + "'.");
			}
			Vector3 placement = GetPlacement(job);
			GameObject val2 = Items.SpawnItem(val, placement, Quaternion.identity);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("REPOLib returned no spawned item object.");
			}
			SpawnedObjects.Add(new SpawnedObjectRecord
			{
				Instance = val2,
				Name = val.itemName,
				Kind = SpawnKind.Item,
				IsWeapon = IsWeaponItem(val)
			});
			AppendName(job, val.itemName, 1);
			job.Spawned++;
		}

		private static void SpawnCartStep(SpawnJob job)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			string text = FindCartItemName(job.Selector);
			if (text == null)
			{
				throw new InvalidOperationException("No cart item matches '" + job.Selector + "'.");
			}
			Vector3 placement = GetPlacement(job);
			GameObject val = PhotonNetwork.InstantiateRoomObject("Items/" + text, placement, Quaternion.identity, (byte)0, (object[])null);
			if ((Object)(object)val == (Object)null)
			{
				throw new InvalidOperationException("Photon could not spawn the cart item '" + text + "'.");
			}
			SpawnedObjects.Add(new SpawnedObjectRecord
			{
				Instance = val,
				Name = text,
				Kind = SpawnKind.Cart,
				IsWeapon = false
			});
			AppendName(job, text, 1);
			job.Spawned++;
		}

		private static Vector3 GetPlacement(SpawnJob job)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return GetPlacement(job.Placement, job.Anchor, job.ReservedPositions);
		}

		private static Vector3 GetPlacement(string placement, Vector3 anchor, List<Vector3> reservedPositions)
		{
			//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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (placement == "at-player")
			{
				return anchor + Vector3.up * 1.5f;
			}
			if (placement == "near-player")
			{
				Vector3 val = Random.insideUnitSphere * 3f;
				val.y = Math.Abs(val.y) + 1f;
				return anchor + val;
			}
			if (!TryFindClearPosition(anchor, reservedPositions, out var result))
			{
				throw new InvalidOperationException("No additional collision-free placement was found.");
			}
			reservedPositions.Add(result);
			return result;
		}

		private static bool TryFindClearPosition(Vector3 origin, List<Vector3> reserved, out Vector3 result)
		{
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			LevelGenerator instance = LevelGenerator.Instance;
			List<LevelPoint> list = (((Object)(object)instance == (Object)null) ? null : instance.LevelPathPoints);
			int num = EnemyClearancePolicy.BuildGameplaySolidMask((Func<string, int>)LayerMask.NameToLayer);
			for (int i = 0; i < 500; i++)
			{
				Vector3 val;
				if (list != null && list.Count > 0 && i % 2 == 0)
				{
					val = ((Component)list[Random.Range(0, list.Count)]).transform.position;
				}
				else
				{
					float num2 = Random.Range(0f, MathF.PI * 2f);
					float num3 = Random.Range(4f, 30f);
					val = origin + new Vector3(Mathf.Cos(num2), 0f, Mathf.Sin(num2)) * num3;
				}
				Vector3 val2 = SemiFunc.EnemyRoamFindPoint(val) + Vector3.up * 1.75f;
				bool flag = false;
				foreach (Vector3 item in reserved)
				{
					if (Vector3.Distance(val2, item) < 4f)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					continue;
				}
				Collider[] array = Physics.OverlapBox(val2, new Vector3(1.35f, 1.25f, 1.35f), Quaternion.identity, num, (QueryTriggerInteraction)1);
				bool flag2 = false;
				Collider[] array2 = array;
				foreach (Collider val3 in array2)
				{
					if ((Object)(object)val3 != (Object)null && !val3.isTrigger)
					{
						flag2 = true;
						break;
					}
				}
				if (!flag2)
				{
					result = val2;
					return true;
				}
			}
			result = Vector3.zero;
			return false;
		}

		private static bool TryFindClearEnemyPosition(Vector3 origin, List<EnemyPlacementReservation> reserved, EnemyClearanceVolume clearance, out Vector3 result)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			LevelGenerator instance = LevelGenerator.Instance;
			List<LevelPoint> list = (((Object)(object)instance == (Object)null) ? null : instance.LevelPathPoints);
			int num = EnemyClearancePolicy.BuildGameplaySolidMask((Func<string, int>)LayerMask.NameToLayer);
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < 500; i++)
			{
				Vector3 val;
				if (list != null && list.Count > 0 && i % 2 == 0)
				{
					val = ((Component)list[Random.Range(0, list.Count)]).transform.position;
				}
				else
				{
					float num2 = Random.Range(0f, MathF.PI * 2f);
					float num3 = Random.Range(4f, 30f);
					val = origin + new Vector3(Mathf.Cos(num2), 0f, Mathf.Sin(num2)) * num3;
				}
				Vector3 val2 = SemiFunc.EnemyRoamFindPoint(val);
				bool flag = false;
				foreach (EnemyPlacementReservation item in reserved)
				{
					float num4 = val2.x - item.Position.x;
					float num5 = val2.z - item.Position.z;
					float num6 = clearance.HorizontalRadius + item.HorizontalRadius + 0.5f;
					if (num4 * num4 + num5 * num5 < num6 * num6)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					continue;
				}
				Collider[] array = Physics.OverlapBox(val2 + clearance.CenterOffset, clearance.HalfExtents, Quaternion.identity, num, (QueryTriggerInteraction)1);
				bool flag2 = false;
				Collider[] array2 = array;
				foreach (Collider val3 in array2)
				{
					if ((Object)(object)val3 != (Object)null && !val3.isTrigger)
					{
						string text = LayerMask.LayerToName(((Component)val3).gameObject.layer);
						string key = (string.IsNullOrEmpty(text) ? ((Component)val3).gameObject.layer.ToString() : text) + ":" + ((Object)val3).name;
						dictionary.TryGetValue(key, out var value);
						dictionary[key] = value + 1;
						flag2 = true;
						break;
					}
				}
				if (!flag2)
				{
					reserved.Add(new EnemyPlacementReservation(val2, clearance.HorizontalRadius));
					result = val2;
					return true;
				}
			}
			string text2 = string.Empty;
			int num7 = 0;
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				if (num7 >= 8)
				{
					break;
				}
				if (text2.Length > 0)
				{
					text2 += ", ";
				}
				text2 = text2 + item2.Key + " x" + item2.Value;
				num7++;
			}
			Plugin.Log.LogWarning((object)$"Enemy clearance rejected all candidates. center={clearance.CenterOffset}, halfExtents={clearance.HalfExtents}, radius={clearance.HorizontalRadius:0.00}, mask={num}, blockers=[{text2}]");
			result = Vector3.zero;
			return false;
		}

		private static EnemyClearanceVolume GetEnemyClearanceVolume(EnemySetup setup)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(-0.9f, 0.1f, -0.9f);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0.9f, 2.4f, 0.9f);
			if ((Object)(object)setup != (Object)null && setup.spawnObjects != null)
			{
				foreach (PrefabRef spawnObject in setup.spawnObjects)
				{
					GameObject val3 = ((PrefabRef<GameObject>)(object)spawnObject)?.Prefab;
					if (!((Object)(object)val3 == (Object)null) && TryGetAggregatePrefabBounds(val3, out var aggregate))
					{
						Vector3 position = val3.transform.position;
						val = Vector3.Min(val, ((Bounds)(ref aggregate)).min - position);
						val2 = Vector3.Max(val2, ((Bounds)(ref aggregate)).max - position);
					}
				}
			}
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(0.2f, 0.2f, 0.2f);
			val -= val4;
			val2 += val4;
			val.y = EnemyClearancePolicy.ClampProbeBottomOffset(val.y);
			Vector3 centerOffset = (val + val2) * 0.5f;
			Vector3 halfExtents = (val2 - val) * 0.5f;
			float num = Mathf.Max(Mathf.Abs(val.x), Mathf.Abs(val2.x));
			float num2 = Mathf.Max(Mathf.Abs(val.z), Mathf.Abs(val2.z));
			float horizontalRadius = Mathf.Sqrt(num * num + num2 * num2);
			return new EnemyClearanceVolume(centerOffset, halfExtents, horizontalRadius);
		}

		private static bool TryGetAggregatePrefabBounds(GameObject prefab, out Bounds aggregate)
		{
			//IL_0001: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			aggregate = default(Bounds);
			bool found = false;
			NavMeshAgent[] componentsInChildren = prefab.GetComponentsInChildren<NavMeshAgent>(true);
			Bounds candidate = default(Bounds);
			foreach (NavMeshAgent val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 lossyScale = ((Component)val).transform.lossyScale;
					float num = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z));
					float num2 = Mathf.Abs(lossyScale.y);
					if (EnemyClearancePolicy.IsNavigationEnvelopeUsable(val.radius, val.height, val.baseOffset, num, num2))
					{
						float num3 = val.radius * num;
						float num4 = val.height * num2;
						float num5 = val.baseOffset * num2;
						((Bounds)(ref candidate))..ctor(((Component)val).transform.position + Vector3.up * (num5 + num4 * 0.5f), new Vector3(num3 * 2f, num4, num3 * 2f));
						EncapsulateBounds(ref aggregate, ref found, candidate);
					}
				}
			}
			if (found && HasUsableBounds(aggregate))
			{
				return true;
			}
			aggregate = default(Bounds);
			found = false;
			Collider[] componentsInChildren2 = prefab.GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if (!((Object)(object)val2 == (Object)null) && EnemyClearancePolicy.IsBodyGeometryEligible(val2.enabled, val2.isTrigger, IsActiveInPrefabHierarchy(((Component)val2).transform, prefab.transform), (Object)(object)val2.attachedRigidbody != (Object)null))
				{
					Bounds bounds = val2.bounds;
					if (HasUsableBounds(bounds))
					{
						EncapsulateBounds(ref aggregate, ref found, bounds);
					}
				}
			}
			if (found && !HasUsableBounds(aggregate))
			{
				aggregate = default(Bounds);
				found = false;
			}
			if (!found)
			{
				Renderer[] componentsInChildren3 = prefab.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val3 in componentsInChildren3)
				{
					if (!((Object)(object)val3 == (Object)null) && EnemyClearancePolicy.IsBodyGeometryEligible(val3.enabled, isTrigger: false, IsActiveInPrefabHierarchy(((Component)val3).transform, prefab.transform), attachedToRigidbody: false))
					{
						Bounds bounds2 = val3.bounds;
						if (HasUsableBounds(bounds2))
						{
							EncapsulateBounds(ref aggregate, ref found, bounds2);
						}
					}
				}
			}
			if (found)
			{
				return HasUsableBounds(aggregate);
			}
			return false;
		}

		private static bool IsActiveInPrefabHierarchy(Transform componentTransform, Transform prefabRoot)
		{
			if ((Object)(object)componentTransform == (Object)null || (Object)(object)prefabRoot == (Object)null)
			{
				return false;
			}
			Transform val = componentTransform;
			while ((Object)(object)val != (Object)null)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					return false;
				}
				if ((Object)(object)val == (Object)(object)prefabRoot)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool HasUsableBounds(Bounds candidate)
		{
			//IL_0002: 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_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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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)
			Vector3 center = ((Bounds)(ref candidate)).center;
			Vector3 size = ((Bounds)(ref candidate)).size;
			if (float.IsNaN(center.x) || float.IsInfinity(center.x) || float.IsNaN(center.y) || float.IsInfinity(center.y) || float.IsNaN(center.z) || float.IsInfinity(center.z) || float.IsNaN(size.x) || float.IsInfinity(size.x) || float.IsNaN(size.y) || float.IsInfinity(size.y) || float.IsNaN(size.z) || float.IsInfinity(size.z))
			{
				return false;
			}
			return ((Vector3)(ref size)).sqrMagnitude > 1E-06f;
		}

		private static void EncapsulateBounds(ref Bounds aggregate, ref bool found, Bounds candidate)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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)
			if (!found)
			{
				aggregate = candidate;
				found = true;
			}
			else
			{
				((Bounds)(ref aggregate)).Encapsulate(candidate);
			}
		}

		private static void DespawnEnemies(ControlRequest request, string selector, int keep)
		{
			EnemyDirector instance = EnemyDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				throw new InvalidOperationException("The enemy director is unavailable.");
			}
			keep = Math.Max(0, keep);
			List<EnemyParent> list = new List<EnemyParent>();
			EnemyParent[] array = instance.enemiesSpawned.ToArray();
			foreach (EnemyParent val in array)
			{
				if (!((Object)(object)val == (Object)null) && (selector.Equals("all", StringComparison.OrdinalIgnoreCase) || val.enemyName.IndexOf(selector, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					list.Add(val);
				}
			}
			int num = 0;
			for (int j = keep; j < list.Count; j++)
			{
				EnemyParent val2 = list[j];
				instance.enemiesSpawned.Remove(val2);
				PhotonNetwork.Destroy(((Component)val2).gameObject);
				num++;
			}
			Complete(request, $"OK Despawned {num} matching enemy object(s); kept {Math.Min(keep, list.Count)}.");
		}

		private static void DespawnItems(ControlRequest request, string selector)
		{
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				throw new InvalidOperationException("Only the host can despawn network items.");
			}
			bool flag = selector.Equals("weapon", StringComparison.OrdinalIgnoreCase) || selector.Equals("weapons", StringComparison.OrdinalIgnoreCase);
			int num = 0;
			for (int num2 = SpawnedObjects.Count - 1; num2 >= 0; num2--)
			{
				SpawnedObjectRecord spawnedObjectRecord = SpawnedObjects[num2];
				if ((Object)(object)spawnedObjectRecord.Instance == (Object)null)
				{
					SpawnedObjects.RemoveAt(num2);
					continue;
				}
				if (spawnedObjectRecord.Kind != SpawnKind.Item && spawnedObjectRecord.Kind != SpawnKind.Cart)
				{
					continue;
				}
				bool num3;
				if (!flag)
				{
					if (selector.Equals("all", StringComparison.OrdinalIgnoreCase))
					{
						goto IL_00bd;
					}
					num3 = spawnedObjectRecord.Name.IndexOf(selector, StringComparison.OrdinalIgnoreCase) >= 0;
				}
				else
				{
					num3 = spawnedObjectRecord.IsWeapon;
				}
				if (!num3)
				{
					continue;
				}
				goto IL_00bd;
				IL_00bd:
				DestroySpawnedObject(spawnedObjectRecord);
				SpawnedObjects.RemoveAt(num2);
				num++;
			}
			Complete(request, $"OK Despawned {num} matching bridge-spawned item object(s) for '{selector}'.");
		}

		private static void DespawnSpawnedObjects(ControlRequest request, string kindText, string selector, int requested)
		{
			SpawnKind? spawnKind = ParseSpawnKind(kindText);
			if (!spawnKind.HasValue && !kindText.Equals("all", StringComparison.OrdinalIgnoreCase))
			{
				throw new InvalidOperationException("Unknown spawned-object kind '" + kindText + "'.");
			}
			int num = ((requested < 0) ? int.MaxValue : Mathf.Clamp(requested, 1, 500));
			int num2 = 0;
			int num3 = SpawnedObjects.Count - 1;
			while (num3 >= 0 && num2 < num)
			{
				SpawnedObjectRecord spawnedObjectRecord = SpawnedObjects[num3];
				if ((Object)(object)spawnedObjectRecord.Instance == (Object)null)
				{
					SpawnedObjects.RemoveAt(num3);
				}
				else
				{
					bool num4 = !spawnKind.HasValue || spawnedObjectRecord.Kind == spawnKind.Value || (spawnKind.Value == SpawnKind.Item && spawnedObjectRecord.Kind == SpawnKind.Cart);
					bool flag = selector.Equals("all", StringComparison.OrdinalIgnoreCase) || spawnedObjectRecord.Name.Equals(selector, StringComparison.OrdinalIgnoreCase);
					if (num4 && flag)
					{
						DestroySpawnedObject(spawnedObjectRecord);
						SpawnedObjects.RemoveAt(num3);
						num2++;
					}
				}
				num3--;
			}
			Complete(request, $"OK Despawned {num2} matching mod-spawned {kindText} object(s) for '{selector}'.");
		}

		private static SpawnKind? ParseSpawnKind(string value)
		{
			if (value.Equals("enemy", StringComparison.OrdinalIgnoreCase))
			{
				return SpawnKind.Enemy;
			}
			if (value.Equals("valuable", StringComparison.OrdinalIgnoreCase) || value.Equals("loot", StringComparison.OrdinalIgnoreCase))
			{
				return SpawnKind.Loot;
			}
			if (value.Equals("item", StringComparison.OrdinalIgnoreCase))
			{
				return SpawnKind.Item;
			}
			if (value.Equals("cart", StringComparison.OrdinalIgnoreCase))
			{
				return SpawnKind.Cart;
			}
			return null;
		}

		private static void DestroySpawnedObject(SpawnedObjectRecord record)
		{
			if (record == null || (Object)(object)record.Instance == (Object)null)
			{
				return;
			}
			if (record.Kind == SpawnKind.Enemy)
			{
				EnemyParent val = record.Instance.GetComponent<EnemyParent>() ?? record.Instance.GetComponentInChildren<EnemyParent>();
				if ((Object)(object)val != (Object)null)
				{
					DestroyEnemyInstance(val, EnemyDirector.instance);
					return;
				}
			}
			else if (record.Kind == SpawnKind.Loot && (Object)(object)ValuableDirector.instance != (Object)null)
			{
				IList list = GetField(ValuableDirector.instance, "valuableList") as IList;
				ValuableObject val2 = record.Instance.GetComponent<ValuableObject>() ?? record.Instance.GetComponentInChildren<ValuableObject>();
				if (list != null && (Object)(object)val2 != (Object)null)
				{
					list.Remove(val2);
				}
			}
			else if ((record.Kind == SpawnKind.Item || record.Kind == SpawnKind.Cart) && (Object)(object)ItemManager.instance != (Object)null)
			{
				ItemAttributes val3 = record.Instance.GetComponent<ItemAttributes>() ?? record.Instance.GetComponentInChildren<ItemAttributes>();
				if ((Object)(object)val3 != (Object)null)
				{
					ItemManager.instance.spawnedItems.Remove(val3);
				}
			}
			if (PhotonNetwork.InRoom)
			{
				PhotonNetwork.Destroy(record.Instance);
			}
			else
			{
				Object.Destroy((Object)(object)record.Instance);
			}
		}

		private static void SetAutomaticEnemies(ControlRequest request, string setting)
		{
			EnemyDirector instance = EnemyDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				throw new InvalidOperationException("The enemy director is unavailable.");
			}
			bool flag;
			if (setting.Equals("on", StringComparison.OrdinalIgnoreCase) || setting == "1" || setting.Equals("true", StringComparison.OrdinalIgnoreCase))
			{
				flag = true;
			}
			else
			{
				if (!setting.Equals("off", StringComparison.OrdinalIgnoreCase) && !(setting == "0") && !setting.Equals("false", StringComparison.OrdinalIgnoreCase))
				{
					throw new InvalidOperationException("Auto setting must be on or off.");
				}
				flag = false;
			}
			((Behaviour)instance).enabled = flag;
			Complete(request, "OK Automatic enemy spawning is " + (flag ? "enabled." : "disabled."));
		}

		private static void UnstickLoot(ControlRequest request)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			ValuableDirector instance = ValuableDirector.instance;
			PlayerAvatar val = RequireRequestPlayer(request);
			IList obj = (GetField(instance, "valuableList") as IList) ?? throw new InvalidOperationException("The tracked loot list is unavailable.");
			List<PhysGrabObject> list = new List<PhysGrabObject>();
			foreach (object item in obj)
			{
				ValuableObject val2 = (ValuableObject)((item is ValuableObject) ? item : null);
				if (!((Object)(object)val2 == (Object)null))
				{
					PhysGrabObject val3 = ((Component)val2).GetComponent<PhysGrabObject>() ?? ((Component)val2).GetComponentInParent<PhysGrabObject>();
					if ((Object)(object)val3 != (Object)null && IsStuck(val3))
					{
						list.Add(val3);
					}
				}
			}
			List<Vector3> list2 = new List<Vector3>();
			int