Decompiled source of Chat Commands v1.2.5

BepInEx/plugins/ChatCommands/ChatCommands.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using ChatCommands.Attributes;
using ChatCommands.BuiltinCommands;
using ChatCommands.Parsing;
using ChatCommands.Utils;
using ChatCommands.Utils.ParameterTypes;
using ComputerysModdingUtilities;
using FishNet;
using FishNet.Connection;
using FishNet.Managing.Object;
using FishNet.Object;
using HarmonyLib;
using HeathenEngineering.DEMO;
using HeathenEngineering.SteamworksIntegration;
using HeathenEngineering.SteamworksIntegration.UI;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Newtonsoft.Json;
using Steamworks;
using TMPro;
using Unity.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: StraftatMod(true)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Heathen.Steamworks")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ChatCommands")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A library mod for straftat that allows developers to create their own chat commands")]
[assembly: AssemblyFileVersion("1.2.5.0")]
[assembly: AssemblyInformationalVersion("1.2.5")]
[assembly: AssemblyProduct("kestrel.straftat.chatcommands")]
[assembly: AssemblyTitle("ChatCommands")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ChatCommands
{
	public static class ChatPatches
	{
		[HarmonyPatch(typeof(LobbyChatUILogic))]
		internal static class LobbyChatUILogicPatch
		{
			[HarmonyPatch("Start")]
			[HarmonyPostfix]
			public static void ModifyPanel(GameObject ___theirChatTemplate, Transform ___messageRoot, List<IChatMessage> ___chatMessages, GameObject ___chatPanel, LobbyManager ___lobbyManager)
			{
				m_lobbyManager = ___lobbyManager;
				m_messageTemplate = ___theirChatTemplate;
				m_messageRoot = ___messageRoot;
				m_chatMessages = ___chatMessages;
			}

			[HarmonyPatch("OnSendChatMessage")]
			[HarmonyPrefix]
			public static bool DetectCommand(TMP_InputField ___inputField)
			{
				string text = ___inputField.text;
				if (!text.StartsWith("/"))
				{
					return true;
				}
				Evaluator.Instance.Evaluate(text.Remove(0, "/".Length));
				return false;
			}
		}

		[HarmonyPatch(typeof(MatchChat))]
		internal static class MatchChatPatch
		{
			private static bool m_activeLast = true;

			[HarmonyPatch("Update")]
			[HarmonyPrefix]
			public static void OpenOnCommandPrefix(GameObject ___ChatBox, TMP_InputField ___inputLine)
			{
				if (Input.GetKeyDown((KeyCode)47) && !___ChatBox.activeSelf)
				{
					___ChatBox.SetActive(true);
					___inputLine.text = "/";
					___inputLine.MoveToEndOfLine(false, true);
				}
				bool activeInHierarchy = ___ChatBox.activeInHierarchy;
				if (!activeInHierarchy && m_activeLast)
				{
					___inputLine.text = string.Empty;
				}
				m_activeLast = activeInHierarchy;
			}
		}

		public const string c_commandPrefix = "/";

		public const KeyCode c_commandHotkey = 47;

		private static LobbyManager m_lobbyManager;

		private static GameObject m_messageTemplate;

		private static Transform m_messageRoot;

		private static List<IChatMessage> m_chatMessages;

		public static void SendChatMessage(string message)
		{
			((LobbyData)(ref m_lobbyManager.Lobby)).SendChatMessage(message);
		}

		public static void ClearChat()
		{
			foreach (IChatMessage chatMessage in m_chatMessages)
			{
				try
				{
					Object.Destroy((Object)(object)chatMessage.GameObject);
				}
				catch
				{
				}
			}
			m_chatMessages.Clear();
		}

		public static void SendSystemMessage(object message, bool showUsername = true, TextAlignmentOptions alignment = 260)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(m_messageTemplate, m_messageRoot);
			val.transform.SetAsLastSibling();
			((LayoutGroup)val.GetComponent<VerticalLayoutGroup>()).padding.right = 0;
			BasicChatMessage component = val.GetComponent<BasicChatMessage>();
			if (component != null)
			{
				TextMeshProUGUI component2 = ((Component)component.username).GetComponent<TextMeshProUGUI>();
				((TMP_Text)component2).alignment = alignment;
				TextMeshProUGUI message2 = component.message;
				((TMP_Text)message2).alignment = alignment;
				((TMP_Text)component2).text = "SYSTEM";
				((TMP_Text)message2).text = message.ToString();
				if (!showUsername)
				{
					((Component)component.username).gameObject.SetActive(false);
				}
				component.IsExpanded = false;
				m_chatMessages.Add((IChatMessage)(object)component);
			}
			else
			{
				Object.Destroy((Object)(object)val);
				Plugin.Logger.LogError((object)$"Failed to send system message \"{message}\" in chat~ null BasicChatMessage.");
			}
		}
	}
	[Flags]
	public enum CommandFlags
	{
		None = 0,
		HostOnly = 1,
		ExplorationOnly = 2,
		IngameOnly = 4,
		Silent = 8,
		TryRunOnHost = 0x10
	}
	public class Command
	{
		public readonly MethodInfo method;

		public readonly string description;

		public readonly CommandFlags flags;

		public readonly string name;

		public readonly string[] aliases;

		public readonly string categoryName;

		public readonly ParameterInfo[] parameterInfos;

		public readonly int maxParameters;

		public readonly int minParameters;

		public readonly int registryPriority;

		public readonly bool hasRequesterParameter;

		public bool isOverriden;

		public Command(MethodInfo method, string name, string description = "no description found", string categoryName = "Misc", CommandFlags flags = CommandFlags.None, int registryPriority = 0, params string[] aliases)
		{
			this.name = name;
			this.aliases = aliases;
			this.method = method;
			this.description = description;
			this.flags = flags;
			this.categoryName = categoryName;
			this.registryPriority = registryPriority;
			parameterInfos = method.GetParameters();
			maxParameters = parameterInfos.Length;
			minParameters = parameterInfos.Count((ParameterInfo p) => !p.HasDefaultValue);
			if (maxParameters > 0 && Evaluator.IsRequesterParameter(parameterInfos[^1]))
			{
				hasRequesterParameter = true;
				maxParameters--;
			}
		}

		public object Invoke(object[] args)
		{
			return method.Invoke(null, args);
		}
	}
	public static class CommandRegistry
	{
		internal static Dictionary<string, Command> Commands { get; private set; } = new Dictionary<string, Command>();


		internal static HashSet<string> Categories { get; private set; } = new HashSet<string>();


		public static void RegisterCommandsFromAssembly(Assembly assembly)
		{
			PopulateFromAssembly(assembly);
		}

		public static void RegisterCommandsFromAssembly()
		{
			PopulateFromAssembly(Assembly.GetCallingAssembly());
		}

		public static bool CommandExists(string alias)
		{
			return Commands.ContainsKey(alias);
		}

		public static bool CategoryExists(string categoryName)
		{
			return Categories.Contains(categoryName.ToLower());
		}

		public static bool TryGet(string alias, out Command command)
		{
			return Commands.TryGetValue(alias, out command);
		}

		private static Command[] GetCollisions(Command command)
		{
			HashSet<Command> hashSet = new HashSet<Command>();
			foreach (string item in command.aliases.Append(command.name))
			{
				if (TryGet(item, out var command2))
				{
					hashSet.Add(command2);
				}
			}
			return hashSet.ToArray();
		}

		private static void Add(Command command)
		{
			Categories.Add(command.categoryName.ToLower());
			Commands.Add(command.name, command);
			string[] aliases = command.aliases;
			foreach (string key in aliases)
			{
				Commands.Add(key, command);
			}
		}

		private static void AddOverride(Command command)
		{
			Categories.Add(command.categoryName.ToLower());
			Commands[command.name] = command;
			string[] aliases = command.aliases;
			foreach (string key in aliases)
			{
				Commands[key] = command;
			}
		}

		internal static void RegisterCommand(Command command)
		{
			Command[] collisions = GetCollisions(command);
			if (collisions.Length == 0)
			{
				Add(command);
			}
			else if (collisions.All((Command c) => c.registryPriority < command.registryPriority))
			{
				Command[] array = collisions;
				foreach (Command command2 in array)
				{
					foreach (string item in command2.aliases.Append(command2.name))
					{
						Commands.Remove(item);
					}
				}
				command.isOverriden = true;
				AddOverride(command);
			}
			else if (collisions.Any((Command c) => c.registryPriority == command.registryPriority))
			{
				Assembly definingAssembly = command.method.DeclaringType?.Assembly ?? Assembly.GetCallingAssembly();
				LogConflictError(command.aliases.Prepend(command.name).ToArray(), command.registryPriority, definingAssembly);
			}
		}

		private static void PopulateFromAssembly(Assembly assembly)
		{
			Plugin.Logger.LogInfo((object)("Registering commands from \"" + assembly.GetName().Name + "\""));
			foreach (MethodInfo item in from method in assembly.GetTypes().SelectMany((Type type) => type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
				where method.IsDefined(typeof(CommandAttribute), inherit: false)
				select method)
			{
				Type declaringType = item.DeclaringType;
				CommandAttribute customAttribute = item.GetCustomAttribute<CommandAttribute>();
				bool flag = item.IsDefined(typeof(CommandAliasesAttribute), inherit: false);
				bool num = item.IsDefined(typeof(CommandOverrideAttribute), inherit: false);
				string categoryName = (((object)declaringType == null || !declaringType.IsDefined(typeof(CommandCategoryAttribute), inherit: false)) ? "Misc" : declaringType.GetCustomAttribute<CommandCategoryAttribute>()?.name);
				int registryPriority = (num ? item.GetCustomAttribute<CommandOverrideAttribute>().priority : 0);
				Command command;
				if (flag)
				{
					CommandAliasesAttribute customAttribute2 = item.GetCustomAttribute<CommandAliasesAttribute>();
					command = new Command(item, customAttribute.name, customAttribute.description, categoryName, customAttribute.flags, registryPriority, customAttribute2.aliases);
				}
				else
				{
					command = new Command(item, customAttribute.name, customAttribute.description, categoryName, customAttribute.flags, registryPriority);
				}
				RegisterCommand(command);
			}
		}

		private static void LogConflictError(string[] problematicCommandNames, int priorityAttempted, Assembly definingAssembly)
		{
			Plugin.Logger.LogError((object)($"Error when registering command \"{problematicCommandNames[0]}\" from \"{definingAssembly.GetName().Name}\" w/ priority {priorityAttempted}:" + " a command with the same name or one of the same aliases is already registered with the same priority!"));
			Plugin.Logger.LogError((object)"Command conflicts:");
			for (int i = 0; i < problematicCommandNames.Length; i++)
			{
				if (!TryGet(problematicCommandNames[i], out var command))
				{
					continue;
				}
				StringBuilder stringBuilder = new StringBuilder("\"" + (command.method.DeclaringType?.Assembly.GetName().Name ?? "UNKNOWN ASSEMBLY") + "\" registers [");
				stringBuilder.Append("\"").Append(command.name).Append("\" w/ priority: ")
					.Append(command.registryPriority);
				if (command.aliases.Length != 0)
				{
					stringBuilder.Append(", aliases: ");
					string[] aliases = command.aliases;
					foreach (string value in aliases)
					{
						stringBuilder.Append("\"").Append(value).Append("\" ");
					}
				}
				stringBuilder.Append("\b]");
				Plugin.Logger.LogWarning((object)stringBuilder.ToString());
				stringBuilder.Clear();
			}
		}

		[Obsolete("slow. bad idea.")]
		internal static void PopulateAll()
		{
			foreach (Assembly item in from plugin in Chainloader.PluginInfos.Values
				select (plugin == null) ? null : ((object)plugin.Instance)?.GetType().Assembly into assembly
				where (object)assembly != null
				select assembly)
			{
				PopulateFromAssembly(item);
			}
		}
	}
	public class Evaluator
	{
		[CompilerGenerated]
		private static Evaluator <Instance>k__BackingField;

		public static Evaluator Instance => <Instance>k__BackingField ?? (<Instance>k__BackingField = new Evaluator());

		public void Evaluate(string input)
		{
			Queue<CommandLexer.Token> tokens = new CommandLexer(input).GetTokens();
			List<string> list = new List<string>();
			object obj = null;
			while (tokens.Count > 0)
			{
				CommandLexer.Token token = tokens.Dequeue();
				switch (token.type)
				{
				case CommandLexer.TokenType.Seperator:
					if (list.Count != 0)
					{
						string name = list[0];
						list.RemoveAt(0);
						if (obj != null)
						{
							list.Add(obj.ToString());
							obj = null;
						}
						RunCommand(name, list.ToArray());
						list.Clear();
					}
					break;
				case CommandLexer.TokenType.Pipe:
					if (list.Count != 0)
					{
						string name = list[0];
						list.RemoveAt(0);
						if (obj != null)
						{
							list.Add(obj.ToString());
						}
						obj = RunCommand(name, list.ToArray(), sendResult: false);
						list.Clear();
					}
					break;
				default:
					list.Add(token.content);
					break;
				}
			}
		}

		internal static bool IsRequesterParameter(ParameterInfo parameter)
		{
			if (parameter.ParameterType == typeof(CSteamID) && parameter.Name == "requester")
			{
				return parameter.HasDefaultValue;
			}
			return false;
		}

		private static bool TryParseParameters(Command cmd, CSteamID requester, in string[] stringArgs, out object[] parsedArgs, out string err)
		{
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			int num = stringArgs.Length;
			parsedArgs = new object[cmd.parameterInfos.Length];
			if (num < cmd.minParameters)
			{
				err = string.Format("Too few parameters: the command \"{0}\" expects at least {1}, but {2} {3} provided!", cmd.name, cmd.minParameters, num, (num == 1) ? "was" : "were");
				return false;
			}
			if (num > cmd.maxParameters)
			{
				err = string.Format("Too many parameters: the command \"{0}\" expects at most {1}, but {2} {3} provided!", cmd.name, cmd.maxParameters, num, (num == 1) ? "was" : "were");
				return false;
			}
			for (int i = 0; i < cmd.parameterInfos.Length; i++)
			{
				if (i < num)
				{
					Type parameterType = cmd.parameterInfos[i].ParameterType;
					try
					{
						parsedArgs[i] = ParserLocator.ParseTo(parameterType, stringArgs[i]);
					}
					catch (Exception ex)
					{
						if (ex is NotSupportedException)
						{
							err = "Parameter \"" + cmd.parameterInfos[i].Name + "\" is of type " + parameterType.Name + ", which chat commands does not support!";
						}
						else if (ex is InvalidCastException && ex.Message != "")
						{
							err = "Parameter \"" + cmd.parameterInfos[i].Name + "\" could not be parsed: " + ex.Message;
						}
						else
						{
							err = "Parameter \"" + cmd.parameterInfos[i].Name + "\" is of type " + parameterType.Name + ", but the provided parameter (\"" + stringArgs[i] + "\") could not be converted to it!";
						}
						return false;
					}
				}
				else
				{
					parsedArgs[i] = cmd.parameterInfos[i].DefaultValue;
				}
			}
			if (cmd.hasRequesterParameter)
			{
				parsedArgs[^1] = requester;
			}
			err = null;
			return true;
		}

		private object RunCommand(string name, string[] args, bool sendResult = true)
		{
			//IL_0146: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (!CommandRegistry.TryGet(name, out var command))
			{
				SystemMessage("No command found with name \"" + name + "\".");
				return null;
			}
			if (command.flags.HasFlag(CommandFlags.IngameOnly) && PauseManager.Instance.inMainMenu)
			{
				SystemMessage("The command \"" + name + "\" can only be run while in a game!");
				return null;
			}
			if (command.flags.HasFlag(CommandFlags.ExplorationOnly) && !SceneMotor.Instance.testMap)
			{
				SystemMessage("The command \"" + name + "\" can only be run in exploration mode!");
				return null;
			}
			if (command.flags.HasFlag(CommandFlags.TryRunOnHost) && !InstanceFinder.IsHost)
			{
				if (!MyceliumNetwork.GetPlayerData<bool>(MyceliumNetwork.LobbyHost, "chatCommandsInstalled"))
				{
					SystemMessage("The command \"" + name + "\" can only be run if the lobby host has chat commands installed!");
					return null;
				}
				MyceliumNetwork.RPCTarget(25u, "RPCRunCommand", MyceliumNetwork.LobbyHost, (ReliableType)1, new object[3]
				{
					name,
					JsonConvert.SerializeObject((object)args),
					sendResult
				});
				return null;
			}
			if (command.flags.HasFlag(CommandFlags.HostOnly) && !InstanceFinder.IsHost)
			{
				SystemMessage("The command \"" + name + "\" can only be run as a lobby host!");
				return null;
			}
			if (!TryParseParameters(command, CSteamID.Nil, in args, out var parsedArgs, out var err))
			{
				SystemMessage(err);
				return null;
			}
			try
			{
				object obj = command.Invoke(parsedArgs);
				if (obj != null && !command.flags.HasFlag(CommandFlags.Silent) && sendResult)
				{
					SystemMessage(obj);
				}
				return obj;
			}
			catch (Exception ex)
			{
				Exception innerMostException = ex.GetInnerMostException();
				if (innerMostException is CommandException ex2)
				{
					SystemMessage("Command \"" + name + "\" failed: " + ex2.Message);
				}
				else
				{
					SystemMessage($"Unknown error running command \"{name}\": {innerMostException}");
				}
				return null;
			}
		}

		[CustomRPC]
		private void RPCRunCommand(string name, string jsonArgs, bool sendResult, RPCInfo info)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			string[] stringArgs = JsonConvert.DeserializeObject<string[]>(jsonArgs);
			if (!CommandRegistry.TryGet(name, out var command))
			{
				ReturnSystemMessage("Host could not find a command with name \"" + name + "\". Do they have the same command mods as you?");
				return;
			}
			if (!TryParseParameters(command, info.SenderSteamID, in stringArgs, out var parsedArgs, out var err))
			{
				ReturnSystemMessage(err);
				return;
			}
			try
			{
				object obj = command.Invoke(parsedArgs);
				if (obj != null && !command.flags.HasFlag(CommandFlags.Silent) && sendResult)
				{
					ReturnSystemMessage(obj.ToString());
				}
			}
			catch (Exception ex)
			{
				Exception innerMostException = ex.GetInnerMostException();
				if (innerMostException is CommandException ex2)
				{
					ReturnSystemMessage("Command \"" + name + "\" failed: " + ex2.Message);
				}
				else
				{
					ReturnSystemMessage($"Unknown error running command \"{name}\": {innerMostException}");
				}
			}
			void ReturnSystemMessage(string message)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				MyceliumNetwork.RPCTarget(25u, "RPCSystemMessage", info.SenderSteamID, (ReliableType)1, new object[1] { message });
			}
		}

		[CustomRPC]
		private void RPCSystemMessage(string message)
		{
			SystemMessage(message);
		}

		private static void SystemMessage(object msg)
		{
			ChatPatches.SendSystemMessage(msg, showUsername: true, (TextAlignmentOptions)260);
		}
	}
	internal class CommandLexer
	{
		public enum TokenType
		{
			Identifier,
			NestedString,
			Seperator,
			Pipe
		}

		public readonly struct Token
		{
			public readonly string content;

			public readonly TokenType type;

			public static Token Seperator => new Token(";", TokenType.Seperator);

			public static Token Pipe => new Token("|", TokenType.Pipe);

			public Token(string content, TokenType type)
			{
				this.content = content;
				this.type = type;
			}
		}

		[CompilerGenerated]
		private string <source>P;

		private int m_pos;

		private StringBuilder m_builder;

		public CommandLexer(string source)
		{
			<source>P = source;
			m_builder = new StringBuilder();
			base..ctor();
		}

		private static bool IsSeperator(char c)
		{
			if (c == '\n' || c == ';')
			{
				return true;
			}
			return false;
		}

		private static bool IsPipe(char c)
		{
			if (c == '>' || c == '|')
			{
				return true;
			}
			return false;
		}

		private static bool IsQuote(char c)
		{
			if (c == '"' || c == '\'')
			{
				return true;
			}
			return false;
		}

		private static bool IsIdentifierChar(char c)
		{
			bool flag = char.IsLetterOrDigit(c);
			if (!flag)
			{
				bool flag2;
				switch (c)
				{
				case '(':
				case ')':
				case ',':
				case '-':
				case '.':
				case ':':
				case '_':
					flag2 = true;
					break;
				default:
					flag2 = false;
					break;
				}
				flag = flag2;
			}
			return flag;
		}

		private static bool IsIgnorable(char c)
		{
			if (!IsSeperator(c) && !IsQuote(c) && !IsIdentifierChar(c))
			{
				return !IsPipe(c);
			}
			return false;
		}

		private static char GetEscaped(char c)
		{
			return c switch
			{
				'n' => '\n', 
				'r' => '\r', 
				't' => '\t', 
				'b' => '\b', 
				_ => c, 
			};
		}

		private void SkipIgnorables()
		{
			while (m_pos < <source>P.Length && IsIgnorable(<source>P[m_pos]))
			{
				m_pos++;
			}
		}

		private bool TryGetNextToken(out Token token)
		{
			SkipIgnorables();
			token = default(Token);
			if (m_pos == <source>P.Length)
			{
				return false;
			}
			TokenType tokenType = TokenType.Identifier;
			char c = '\0';
			char c2 = <source>P[m_pos];
			if (IsQuote(c2))
			{
				tokenType = TokenType.NestedString;
				c = c2;
				m_pos++;
			}
			else
			{
				if (IsSeperator(c2))
				{
					m_pos++;
					token = Token.Seperator;
					return true;
				}
				if (IsPipe(c2))
				{
					m_pos++;
					token = Token.Pipe;
					return true;
				}
			}
			while (m_pos < <source>P.Length)
			{
				char c3 = <source>P[m_pos];
				if (tokenType == TokenType.Identifier)
				{
					if (!IsIdentifierChar(c3))
					{
						break;
					}
				}
				else if (c3 == '\\' && m_pos + 1 < <source>P.Length)
				{
					c3 = GetEscaped(<source>P[++m_pos]);
				}
				else if (c3 == c)
				{
					m_pos++;
					break;
				}
				m_builder.Append(c3);
				m_pos++;
			}
			string content = m_builder.ToString();
			token = new Token(content, tokenType);
			m_builder.Clear();
			return true;
		}

		public Queue<Token> GetTokens()
		{
			Queue<Token> queue = new Queue<Token>();
			Token token;
			while (TryGetNextToken(out token))
			{
				queue.Enqueue(token);
			}
			queue.Enqueue(Token.Seperator);
			return queue;
		}
	}
	public class CommandException : Exception
	{
		public CommandException()
		{
		}

		public CommandException(string message)
			: base(message)
		{
		}

		public CommandException(string message, Exception inner)
			: base(message, inner)
		{
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("kestrel.straftat.chatcommands", "ChatCommands", "1.2.5")]
	internal class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		public const uint c_myceliumID = 25u;

		public static readonly string loadBearingColonThree = ":3";

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if (loadBearingColonThree != ":3")
			{
				Application.Quit();
			}
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			BindingCommands.Init();
			AdminCommands.Init();
			CommandRegistry.RegisterCommandsFromAssembly();
			MyceliumNetwork.RegisterNetworkObject((object)Evaluator.Instance, 25u, 0);
			MyceliumNetwork.RegisterNetworkObject((object)TeleportationCommands.Instance, 25u, 0);
			MyceliumNetwork.RegisterPlayerDataKey("chatCommandsInstalled");
			MyceliumNetwork.LobbyEntered += delegate
			{
				MyceliumNetwork.SetPlayerData("chatCommandsInstalled", (object)true);
			};
			new Harmony("kestrel.straftat.chatcommands").PatchAll();
			Logger.LogInfo((object)"Hiiiiiiiiiiii :3");
		}

		private void Start()
		{
			WeaponLoader.Init();
		}

		private void Update()
		{
			BindingCommands.Update();
		}

		private void FixedUpdate()
		{
			BindingCommands.FixedUpdate();
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "kestrel.straftat.chatcommands";

		public const string PLUGIN_NAME = "ChatCommands";

		public const string PLUGIN_VERSION = "1.2.5";
	}
}
namespace ChatCommands.Utils
{
	internal static class CollectionExtensions
	{
		public static IEnumerable<TValue> RandomValues<TKey, TValue>(this IDictionary<TKey, TValue> dict)
		{
			TValue[] values = dict.Values.ToArray();
			int size = dict.Count;
			while (true)
			{
				yield return values[Random.Range(0, size - 1)];
			}
		}
	}
	internal static class ExceptionExtensions
	{
		public static Exception GetInnerMostException(this Exception ex)
		{
			while (ex.InnerException != null && ex != null)
			{
				ex = ex.InnerException;
			}
			return ex;
		}
	}
	internal static class JsonUtils
	{
		public static T FromJsonFile<T>(string path)
		{
			if (!File.Exists(path))
			{
				return default(T);
			}
			return JsonConvert.DeserializeObject<T>(File.ReadAllText(path));
		}

		public static void ToJsonFile<T>(T obj, string path)
		{
			File.WriteAllText(path, JsonConvert.SerializeObject((object)obj, (Formatting)1));
		}
	}
}
namespace ChatCommands.Utils.ParameterTypes
{
	public class Player
	{
		public readonly CSteamID steamID;

		[CompilerGenerated]
		private string <Username>k__BackingField;

		public bool InCurrentLobby => MyceliumNetwork.Players.Contains(steamID);

		public string Username => <Username>k__BackingField ?? SteamFriends.GetFriendPersonaName(steamID);

		public ClientInstance Client => ((IEnumerable<ClientInstance>)ClientInstance.playerInstances.Values).FirstOrDefault((Func<ClientInstance, bool>)((ClientInstance ci) => ci.PlayerSteamID == steamID.m_SteamID));

		public GameObject SpawnedPlayer
		{
			get
			{
				ClientInstance client = Client;
				if (client == null)
				{
					return null;
				}
				return ((Component)client).GetComponent<PlayerManager>().SpawnedObject;
			}
		}

		public Player(CSteamID steamID)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			this.steamID = steamID;
			string friendPersonaName = SteamFriends.GetFriendPersonaName(steamID);
			if (friendPersonaName != "" && friendPersonaName != "[unknown]")
			{
				<Username>k__BackingField = friendPersonaName;
			}
		}

		public static bool TryGetInLobby(string username, out Player player)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			CSteamID[] players = MyceliumNetwork.Players;
			foreach (CSteamID val in players)
			{
				if (string.Equals(SteamFriends.GetFriendPersonaName(val), username, StringComparison.OrdinalIgnoreCase))
				{
					player = new Player(val);
					return true;
				}
			}
			player = null;
			return false;
		}
	}
	public class PlayerParser : IParsingExtension
	{
		public Type Target => typeof(Player);

		public object Parse(string value)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (ulong.TryParse(value, out var result))
			{
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(result);
				CSteamID val2 = val;
				if (((CSteamID)(ref val2)).IsValid())
				{
					return new Player(val);
				}
			}
			if (Player.TryGetInLobby(value, out var player))
			{
				return player;
			}
			throw new InvalidCastException("\"" + value + "\" is not a valid steam id, or no user with that name is in your lobby!");
		}
	}
}
namespace ChatCommands.Parsing
{
	internal class BoolParser : IParsingExtension
	{
		public Type Target => typeof(bool);

		public object Parse(string value)
		{
			if (bool.TryParse(value, out var result))
			{
				return result;
			}
			if (int.TryParse(value, out var result2))
			{
				return result2 > 0;
			}
			throw new InvalidCastException();
		}
	}
	public interface IParsingExtension
	{
		Type Target { get; }

		object Parse(string value);
	}
	internal class KeyCodeParser : IParsingExtension
	{
		private static Dictionary<string, KeyCode> m_alternativeStrings = new Dictionary<string, KeyCode>
		{
			{
				"1",
				(KeyCode)257
			},
			{
				"2",
				(KeyCode)258
			},
			{
				"3",
				(KeyCode)259
			},
			{
				"4",
				(KeyCode)260
			},
			{
				"5",
				(KeyCode)261
			},
			{
				"6",
				(KeyCode)262
			},
			{
				"7",
				(KeyCode)263
			},
			{
				"8",
				(KeyCode)264
			},
			{
				"9",
				(KeyCode)265
			},
			{
				"0",
				(KeyCode)256
			},
			{
				"!",
				(KeyCode)33
			},
			{
				"\"",
				(KeyCode)34
			},
			{
				"#",
				(KeyCode)35
			},
			{
				"$",
				(KeyCode)36
			},
			{
				"&",
				(KeyCode)38
			},
			{
				"'",
				(KeyCode)39
			},
			{
				"(",
				(KeyCode)40
			},
			{
				")",
				(KeyCode)41
			},
			{
				"*",
				(KeyCode)42
			},
			{
				"+",
				(KeyCode)43
			},
			{
				",",
				(KeyCode)44
			},
			{
				"-",
				(KeyCode)45
			},
			{
				".",
				(KeyCode)46
			},
			{
				"/",
				(KeyCode)47
			},
			{
				":",
				(KeyCode)58
			},
			{
				";",
				(KeyCode)59
			},
			{
				"<",
				(KeyCode)60
			},
			{
				"=",
				(KeyCode)61
			},
			{
				">",
				(KeyCode)62
			},
			{
				"?",
				(KeyCode)63
			},
			{
				"@",
				(KeyCode)64
			},
			{
				"[",
				(KeyCode)91
			},
			{
				"\\",
				(KeyCode)92
			},
			{
				"]",
				(KeyCode)93
			},
			{
				"^",
				(KeyCode)94
			},
			{
				"_",
				(KeyCode)95
			},
			{
				"`",
				(KeyCode)96
			},
			{
				"shift",
				(KeyCode)304
			},
			{
				"rshift",
				(KeyCode)303
			},
			{
				"ctrl",
				(KeyCode)306
			},
			{
				"rctrl",
				(KeyCode)305
			},
			{
				"alt",
				(KeyCode)308
			},
			{
				"ralt",
				(KeyCode)307
			},
			{
				"enter",
				(KeyCode)13
			},
			{
				"lwin",
				(KeyCode)311
			},
			{
				"rwin",
				(KeyCode)312
			},
			{
				"apps",
				(KeyCode)319
			},
			{
				"ins",
				(KeyCode)277
			},
			{
				"del",
				(KeyCode)127
			},
			{
				"pgdn",
				(KeyCode)281
			},
			{
				"pgup",
				(KeyCode)280
			},
			{
				"kp_end",
				(KeyCode)257
			},
			{
				"kp_downarrow",
				(KeyCode)258
			},
			{
				"kp_pgdn",
				(KeyCode)259
			},
			{
				"kp_leftarrow",
				(KeyCode)260
			},
			{
				"kp_5",
				(KeyCode)261
			},
			{
				"kp_rightarrow",
				(KeyCode)262
			},
			{
				"kp_home",
				(KeyCode)263
			},
			{
				"kp_uparrow",
				(KeyCode)264
			},
			{
				"kp_pgup",
				(KeyCode)265
			},
			{
				"kp_enter",
				(KeyCode)271
			},
			{
				"kp_ins",
				(KeyCode)256
			},
			{
				"kp_del",
				(KeyCode)266
			},
			{
				"kp_slash",
				(KeyCode)267
			},
			{
				"kp_multiply",
				(KeyCode)268
			},
			{
				"kp_minus",
				(KeyCode)269
			},
			{
				"kp_plus",
				(KeyCode)270
			}
		};

		public Type Target => typeof(KeyCode);

		public object Parse(string value)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (m_alternativeStrings.TryGetValue(value.ToLower(), out var value2))
			{
				return value2;
			}
			if (Enum.TryParse(typeof(KeyCode), value, ignoreCase: true, out object result))
			{
				return result;
			}
			throw new InvalidCastException();
		}
	}
	public static class ParserLocator
	{
		private static Dictionary<Type, IParsingExtension> m_extensions;

		static ParserLocator()
		{
			m_extensions = new Dictionary<Type, IParsingExtension>();
			RegisterExtensionsFromAssembly();
		}

		public static void RegisterExtensionsFromAssembly()
		{
			RegisterExtensionsFromAssembly(Assembly.GetCallingAssembly());
		}

		public static void RegisterExtensionsFromAssembly(Assembly assembly)
		{
			foreach (Type item in from t in assembly.GetTypes()
				where typeof(IParsingExtension).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract
				select t)
			{
				IParsingExtension parsingExtension = Activator.CreateInstance(item) as IParsingExtension;
				m_extensions.TryAdd(parsingExtension.Target, parsingExtension);
			}
		}

		public static object ParseTo(Type type, string input)
		{
			if (type.IsGenericType && !type.IsGenericTypeDefinition && type.GetGenericTypeDefinition() == typeof(Nullable<>))
			{
				type = Nullable.GetUnderlyingType(type);
			}
			if (m_extensions.TryGetValue(type, out var value))
			{
				return value.Parse(input);
			}
			if (typeof(IConvertible).IsAssignableFrom(type))
			{
				return Convert.ChangeType(input, type);
			}
			throw new NotSupportedException("Type not supported.");
		}

		public static bool TryParseTo(Type type, string input, out object result)
		{
			try
			{
				result = ParseTo(type, input);
			}
			catch
			{
				result = null;
				return false;
			}
			return true;
		}

		public static T ParseTo<T>(string input)
		{
			return (T)ParseTo(typeof(T), input);
		}

		public static bool TryParseTo<T>(string input, out T result)
		{
			try
			{
				result = ParseTo<T>(input);
			}
			catch
			{
				result = default(T);
				return false;
			}
			return true;
		}
	}
	public class Vector2Parser : IParsingExtension
	{
		public Type Target => typeof(Vector2);

		public object Parse(string value)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			value = string.Join(' ', value.Split(new char[3] { ',', '(', ')' }, StringSplitOptions.RemoveEmptyEntries));
			string[] array = value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			val.x = float.Parse(array[0].Trim(), CultureInfo.CurrentCulture);
			val.y = float.Parse(array[1].Trim(), CultureInfo.CurrentCulture);
			return val;
		}
	}
	public class Vector3Parser : IParsingExtension
	{
		public Type Target => typeof(Vector3);

		public object Parse(string value)
		{
			//IL_0002: 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)
			Vector3 val = default(Vector3);
			value = string.Join(' ', value.Split(new char[3] { ',', '(', ')' }, StringSplitOptions.RemoveEmptyEntries));
			string[] array = value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			val.x = float.Parse(array[0].Trim(), CultureInfo.CurrentCulture);
			val.y = float.Parse(array[1].Trim(), CultureInfo.CurrentCulture);
			val.z = float.Parse(array[2].Trim(), CultureInfo.CurrentCulture);
			return val;
		}
	}
}
namespace ChatCommands.BuiltinCommands
{
	[CommandCategory("Admin")]
	public static class AdminCommands
	{
		private struct SavedLists
		{
			public HashSet<ulong> bans;

			public HashSet<ulong> ignores;
		}

		[HarmonyPatch(typeof(LobbyChatUILogic))]
		internal static class LobbyChatUILogicPatch
		{
			[HarmonyPatch("HandleChatMessage")]
			[HarmonyPrefix]
			public static bool DontHandleIfIgnored(LobbyChatMsg message)
			{
				return !m_ignoredPlayers.Contains(((UserData)(ref message.sender)).SteamId);
			}
		}

		[HarmonyPatch(typeof(LobbyController))]
		internal static class LobbyControllerPatch
		{
			private static List<PlayerListItem> m_playerListItems;

			public static void KickBannedPlayers(bool isHost)
			{
				foreach (PlayerListItem item in m_playerListItems.Where((PlayerListItem player) => m_bannedPlayers.Contains(player.PlayerSteamID)))
				{
					if (isHost)
					{
						PauseManager.Instance.WriteLog("Kicked \"" + item.PlayerName + "\": banned from this lobby");
						item.KickPlayer();
					}
					else
					{
						PauseManager.Instance.WriteOfflineLog("Warning: the player \"" + item.PlayerName + "\" is on your ban list!");
					}
				}
			}

			[HarmonyPatch("Start")]
			[HarmonyPrefix]
			public static void CapturePlayerlist(List<PlayerListItem> ___PlayerListItems)
			{
				m_playerListItems = ___PlayerListItems;
			}

			[HarmonyPatch("CreateClientPlayerItem")]
			[HarmonyPatch("CreateHostPlayerItem")]
			[HarmonyPostfix]
			public static void HandleBans()
			{
				KickBannedPlayers(InstanceFinder.NetworkManager.IsHost);
			}
		}

		private static HashSet<ulong> m_ignoredPlayers;

		private static HashSet<ulong> m_bannedPlayers;

		private static string m_savePath = Path.Combine(Paths.ConfigPath, "kestrel.straftat.chatcommands.adminlists.json");

		public static void Init()
		{
			SavedLists? savedLists = JsonUtils.FromJsonFile<SavedLists?>(m_savePath);
			m_ignoredPlayers = savedLists?.ignores ?? new HashSet<ulong>();
			m_bannedPlayers = savedLists?.bans ?? new HashSet<ulong>();
		}

		private static void SaveToJson()
		{
			SavedLists obj = default(SavedLists);
			obj.bans = m_bannedPlayers;
			obj.ignores = m_ignoredPlayers;
			JsonUtils.ToJsonFile(obj, m_savePath);
		}

		private static string UsernameOrId(this Player player)
		{
			//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)
			string username = player.Username;
			if (((username == null || username.Length != 0) && !(username == "[unknown]")) || 1 == 0)
			{
				return username;
			}
			CSteamID steamID = player.steamID;
			return ((object)(CSteamID)(ref steamID)).ToString();
		}

		[Command("ignore", "ignores a player, hiding their chat messages.", CommandFlags.None)]
		public static string Ignore(Player target)
		{
			if (!m_ignoredPlayers.Add(target.steamID.m_SteamID))
			{
				throw new CommandException("\"" + target.UsernameOrId() + "\" is already ignored!");
			}
			SaveToJson();
			return "ignored " + target.UsernameOrId();
		}

		[Command("unignore", "unignores a player.", CommandFlags.None)]
		public static string Unignore(Player target)
		{
			if (!m_ignoredPlayers.Remove(target.steamID.m_SteamID))
			{
				throw new CommandException("\"" + target.UsernameOrId() + "\" was not ignored!");
			}
			SaveToJson();
			return "unignored " + target.UsernameOrId();
		}

		[Command("ignorelist", "lists ignored players", CommandFlags.None)]
		public static string ListIgnored()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("<u>ignored players</u>");
			if (m_ignoredPlayers.Count == 0)
			{
				stringBuilder.AppendLine("[none]");
			}
			foreach (ulong ignoredPlayer in m_ignoredPlayers)
			{
				stringBuilder.AppendLine(ignoredPlayer.ToString());
			}
			return stringBuilder.ToString();
		}

		[Command("clearignores", "removes ALL ignores. use with caution!", CommandFlags.None)]
		public static string ClearIgnores()
		{
			m_ignoredPlayers.Clear();
			SaveToJson();
			return "cleared ignored list";
		}

		[Command("ban", "bans a player, automatically kicking them from any of your lobbies.", CommandFlags.None)]
		public static string Ban(Player target)
		{
			if (!m_bannedPlayers.Add(target.steamID.m_SteamID))
			{
				throw new CommandException("\"" + target.UsernameOrId() + "\" is already banned!");
			}
			LobbyControllerPatch.KickBannedPlayers(InstanceFinder.NetworkManager.IsHost);
			SaveToJson();
			return "banned " + target.UsernameOrId();
		}

		[Command("unban", "unbans a player.", CommandFlags.None)]
		public static string Unban(Player target)
		{
			if (!m_bannedPlayers.Remove(target.steamID.m_SteamID))
			{
				throw new CommandException("\"" + target.UsernameOrId() + "\" was not banned");
			}
			SaveToJson();
			return "unbanned " + target.UsernameOrId();
		}

		[Command("banlist", "lists banned players", CommandFlags.None)]
		public static string ListBanned()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("<u>banned players</u>");
			if (m_bannedPlayers.Count == 0)
			{
				stringBuilder.AppendLine("[none]");
			}
			foreach (ulong bannedPlayer in m_bannedPlayers)
			{
				stringBuilder.AppendLine(bannedPlayer.ToString());
			}
			return stringBuilder.ToString();
		}

		[Command("clearbans", "removes ALL bans. use with caution!", CommandFlags.None)]
		public static string ClearBans()
		{
			m_bannedPlayers.Clear();
			SaveToJson();
			return "cleared banned list";
		}
	}
	[CommandCategory("Binding")]
	public static class BindingCommands
	{
		private const KeyCode c_mwheelupKey = 295;

		private const KeyCode c_mwheeldownKey = 296;

		private const string c_mwheelup = "mwheelup";

		private const string c_mwheeldown = "mwheeldown";

		private static Dictionary<KeyCode, List<string>> m_binds;

		private static string m_savePath = Path.Combine(Paths.ConfigPath, "kestrel.straftat.chatcommands.binds.json");

		private static bool m_shouldIgnoreInput = false;

		public static void Init()
		{
			m_binds = JsonUtils.FromJsonFile<Dictionary<KeyCode, List<string>>>(m_savePath) ?? new Dictionary<KeyCode, List<string>>();
		}

		public static void FixedUpdate()
		{
			m_shouldIgnoreInput = AnyInputFieldFocused();
		}

		public static void Update()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (!Cursor.visible)
			{
				float y = Input.mouseScrollDelta.y;
				List<string> value2;
				if (!(y > 0f))
				{
					if (y < 0f && m_binds.TryGetValue((KeyCode)296, out var value))
					{
						value.ForEach(Evaluator.Instance.Evaluate);
					}
				}
				else if (m_binds.TryGetValue((KeyCode)295, out value2))
				{
					value2.ForEach(Evaluator.Instance.Evaluate);
				}
			}
			if (!Input.anyKeyDown || m_shouldIgnoreInput)
			{
				return;
			}
			foreach (string item in m_binds.Where((KeyValuePair<KeyCode, List<string>> bind) => Input.GetKeyDown(bind.Key)).SelectMany((KeyValuePair<KeyCode, List<string>> bind) => bind.Value))
			{
				Evaluator.Instance.Evaluate(item);
			}
		}

		[Command("bind", "binds a command to a specified key", CommandFlags.None)]
		public static string Bind(string key, string command)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			KeyCode key2 = ParseKey(key);
			if (m_binds.TryGetValue(key2, out var value))
			{
				if (value.Contains(command))
				{
					throw new CommandException("bind already exists");
				}
				value.Add(command);
			}
			else if (!m_binds.TryAdd(key2, new List<string>(1) { command }))
			{
				throw new CommandException("unknown error while adding bind");
			}
			JsonUtils.ToJsonFile(m_binds, m_savePath);
			return "bound " + key.ToLower() + " -> \"" + command + "\"";
		}

		[Command("unbind", "removes all bindings from the specified key", CommandFlags.None)]
		public static string Unbind(string key)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			KeyCode key2 = ParseKey(key);
			m_binds.Remove(key2);
			JsonUtils.ToJsonFile(m_binds, m_savePath);
			return "unbound " + key.ToLower();
		}

		private static KeyCode ParseKey(string key)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (!ParserLocator.TryParseTo<KeyCode>(key, out var result) && key != "mwheelup" && key != "mwheeldown")
			{
				throw new CommandException("unknown key: \"" + key + "\"");
			}
			string text = key.ToLower();
			if (!(text == "mwheelup"))
			{
				if (text == "mwheeldown")
				{
					return (KeyCode)296;
				}
				return result;
			}
			return (KeyCode)295;
		}

		[Command("unbindall", "removes all bindings", CommandFlags.None)]
		public static string UnbindAll()
		{
			m_binds.Clear();
			JsonUtils.ToJsonFile(m_binds, m_savePath);
			return "removed all bindings";
		}

		[Command("listbinds", "lists all bound keys", CommandFlags.None)]
		[CommandAliases(new string[] { "key_listboundkeys" })]
		public static string ListBinds()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_004f: 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)
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<KeyCode, List<string>> bind in m_binds)
			{
				KeyCode key = bind.Key;
				string text;
				if ((int)key != 295)
				{
					if ((int)key == 296)
					{
						text = "mwheeldown";
					}
					else
					{
						KeyCode key2 = bind.Key;
						text = ((object)(KeyCode)(ref key2)).ToString();
					}
				}
				else
				{
					text = "mwheelup";
				}
				string text2 = text;
				stringBuilder.Append("\"" + text2 + "\" = ");
				for (int i = 0; i < bind.Value.Count; i++)
				{
					stringBuilder.Append("\"" + bind.Value[i] + "\"");
					if (i < bind.Value.Count - 1)
					{
						stringBuilder.Append(", ");
					}
				}
				stringBuilder.Append("\n");
			}
			string text3 = stringBuilder.ToString();
			if (!(text3 == string.Empty))
			{
				return text3;
			}
			return "no binds";
		}

		private static bool AnyInputFieldFocused()
		{
			GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject;
			if (!Object.op_Implicit((Object)(object)currentSelectedGameObject))
			{
				return false;
			}
			TMP_InputField component = currentSelectedGameObject.GetComponent<TMP_InputField>();
			if (Object.op_Implicit((Object)(object)component) && component.isFocused)
			{
				return true;
			}
			InputField component2 = currentSelectedGameObject.GetComponent<InputField>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				return component2.isFocused;
			}
			return false;
		}
	}
	[CommandCategory("Fun")]
	public static class FunCommands
	{
		private const CommandFlags c_weaponCommandFlags = CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost;

		private static bool m_weaponRainEnabled;

		private static GameObject SteamIDToPlayer(CSteamID requester)
		{
			//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)
			ClientInstance? obj = ((IEnumerable<ClientInstance>)ClientInstance.playerInstances.Values).FirstOrDefault((Func<ClientInstance, bool>)((ClientInstance ci) => ci.PlayerSteamID == requester.m_SteamID));
			if (obj == null)
			{
				return null;
			}
			return ((Component)obj).GetComponent<PlayerManager>().SpawnedObject;
		}

		private static Transform SteamIDToTransform(CSteamID requester)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!(requester == default(CSteamID)))
			{
				return SteamIDToPlayer(requester).transform;
			}
			return ((Component)Settings.Instance.localPlayer).transform;
		}

		[Command("prop", "spawns a prop", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost)]
		[CommandAliases(new string[] { "p" })]
		public static void Prop(string propName, int count = 1, CSteamID requester = default(CSteamID))
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			if (WeaponLoader.TryGetProp(propName, out var prefab))
			{
				Transform val = SteamIDToTransform(requester);
				for (int i = 0; i < count; i++)
				{
					GameObject gameObject = ((Component)Object.Instantiate<PhysicsProp>(prefab, val.position + Vector3.up * 0.35f, val.rotation)).gameObject;
					InstanceFinder.ServerManager.Spawn(gameObject, (NetworkConnection)null);
				}
				return;
			}
			throw new CommandException("No prop found with name " + propName);
		}

		[Command("weapon", "spawns a weapon", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost)]
		[CommandAliases(new string[] { "w" })]
		public static void Weapon(string weaponName, int count = 1, CSteamID requester = default(CSteamID))
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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)
			if (WeaponLoader.TryGetWeapon(weaponName, out var prefab))
			{
				Transform val = SteamIDToTransform(requester);
				for (int i = 0; i < count; i++)
				{
					GameObject gameObject = ((Component)Object.Instantiate<Weapon>(prefab, val.position, val.rotation)).gameObject;
					InstanceFinder.ServerManager.Spawn(gameObject, (NetworkConnection)null);
					gameObject.GetComponent<ItemBehaviour>().DispenserDrop(Vector3.zero);
				}
				return;
			}
			throw new CommandException("No weapon found with name " + weaponName);
		}

		[Command("randomweapon", "spawns a random weapon", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost)]
		[CommandAliases(new string[] { "rw" })]
		public static void RandomWeapon(int count = 1, CSteamID requester = default(CSteamID))
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			Weapon[] array = WeaponLoader.RandomWeapons(count);
			Transform val = SteamIDToTransform(requester);
			Weapon[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				GameObject gameObject = ((Component)Object.Instantiate<Weapon>(array2[i], val.position, val.rotation)).gameObject;
				InstanceFinder.ServerManager.Spawn(gameObject, (NetworkConnection)null);
				gameObject.GetComponent<ItemBehaviour>().DispenserDrop(Vector3.zero);
			}
		}

		[Command("weaponrain", "toggles weapon rain", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost)]
		public static void ToggleWeaponRain(CSteamID requester = default(CSteamID))
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			m_weaponRainEnabled = !m_weaponRainEnabled;
			if (m_weaponRainEnabled)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(WeaponRain(SteamIDToTransform(requester)));
			}
		}

		private static IEnumerator WeaponRain(Transform playerTransform)
		{
			Vector3 val2 = default(Vector3);
			while (m_weaponRainEnabled)
			{
				Weapon obj = WeaponLoader.RandomWeapon();
				Vector2 val = Random.insideUnitCircle * 10f;
				((Vector3)(ref val2))..ctor(playerTransform.position.x + val.x, playerTransform.position.y + 10f, playerTransform.position.z + val.y);
				GameObject gameObject = ((Component)Object.Instantiate<Weapon>(obj, val2, playerTransform.rotation)).gameObject;
				InstanceFinder.ServerManager.Spawn(gameObject, (NetworkConnection)null);
				gameObject.GetComponent<ItemBehaviour>().DispenserDrop(Vector3.zero);
				yield return (object)new WaitForSeconds(0.1f);
			}
		}

		[Command("clearweapons", "removes all spawned weapons in the scene", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly | CommandFlags.TryRunOnHost)]
		public static void ClearWeapons()
		{
			//IL_0000: 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)
			Scene activeScene = SceneManager.GetActiveScene();
			foreach (GameObject item in from w in ((Scene)(ref activeScene)).GetRootGameObjects()
				where Object.op_Implicit((Object)(object)w.GetComponent<Weapon>()) && Object.op_Implicit((Object)(object)w.GetComponent<Rigidbody>())
				select w)
			{
				InstanceFinder.ServerManager.Despawn(item, (DespawnType?)null);
				Object.Destroy((Object)(object)item);
			}
		}

		[Command("fling", "flings you", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly)]
		public static void Fling(int magnitude)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			FirstPersonController localPlayer = Settings.Instance.localPlayer;
			localPlayer.CustomAddForce(((Component)localPlayer.playerCamera).transform.forward, (float)magnitude);
		}
	}
	[CommandCategory("Input")]
	public static class InputCommands
	{
		private static int m_mouseDownFrames;

		private static ButtonControl m_buttonControl;

		[Command("jump", "triggers a jump", CommandFlags.None)]
		public static void Jump()
		{
			//IL_0017: 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)
			PauseManager.Instance.chatting = false;
			Settings.Instance.localPlayer.Jump(default(CallbackContext));
		}

		[Command("click", "triggers a click with the specified mouse button, left by default", CommandFlags.None)]
		public static void Click(int button = 1)
		{
			m_buttonControl = (ButtonControl)(button switch
			{
				1 => Mouse.current.leftButton, 
				2 => Mouse.current.rightButton, 
				3 => Mouse.current.middleButton, 
				4 => Mouse.current.forwardButton, 
				5 => Mouse.current.backButton, 
				_ => throw new CommandException($"invalid mouse button: {button}"), 
			});
			m_mouseDownFrames = 0;
			InputSystem.onBeforeUpdate += QueueMDown;
		}

		private static void QueueMDown()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			InputEventPtr val = default(InputEventPtr);
			NativeArray<byte> val2 = StateEvent.From((InputDevice)(object)Mouse.current, ref val, (Allocator)2);
			try
			{
				InputControlExtensions.WriteValueIntoEvent<float>((InputControl<float>)(object)m_buttonControl, (float)(1 - m_mouseDownFrames), val);
				InputSystem.QueueEvent(val);
			}
			finally
			{
				((IDisposable)val2).Dispose();
			}
			if (++m_mouseDownFrames > 1)
			{
				InputSystem.onBeforeUpdate -= QueueMDown;
			}
		}
	}
	[CommandCategory("Teleportation")]
	public class TeleportationCommands
	{
		[CompilerGenerated]
		private static TeleportationCommands <Instance>k__BackingField;

		private const CommandFlags c_tpCommandFlags = CommandFlags.ExplorationOnly | CommandFlags.IngameOnly;

		private static Vector3? m_location;

		private static Vector3? m_rotation;

		public static TeleportationCommands Instance => <Instance>k__BackingField ?? (<Instance>k__BackingField = new TeleportationCommands());

		[Command("saveloc", "saves your current location and rotation", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly)]
		[CommandAliases(new string[] { "tps" })]
		public static void SaveLoc()
		{
			//IL_0011: 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)
			FirstPersonController localPlayer = Settings.Instance.localPlayer;
			m_location = ((Component)localPlayer).transform.position;
			m_rotation = PlayerEulerAngles(localPlayer);
		}

		[Command("loadloc", "loads your saved location and, optionally, rotation", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly)]
		[CommandAliases(new string[] { "tpl" })]
		public static void LoadLoc(bool includeRotation = true, bool cancelMovement = true)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			Vector3? location = m_location;
			if (!location.HasValue)
			{
				throw new CommandException("No location is saved!");
			}
			if (includeRotation)
			{
				location = m_rotation;
				if (!location.HasValue)
				{
					throw new CommandException("No rotation is saved!");
				}
			}
			TeleportLocalPlayer(m_location.Value, includeRotation ? m_rotation : null, cancelMovement);
		}

		[Command("teleport", "teleports you to a specific location with a specific rotation", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly)]
		[CommandAliases(new string[] { "tp" })]
		public static void Teleport(Vector3 location, Vector3? rotation = null, bool cancelMovement = true)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			TeleportLocalPlayer(location, rotation, cancelMovement);
		}

		[Command("teleportplayer", "teleports a player to another player. the target must have chat commands installed.", CommandFlags.ExplorationOnly | CommandFlags.IngameOnly)]
		[CommandAliases(new string[] { "tpp" })]
		public static void TeleportPlayer(Player target, Player destination, bool includeRotation = false, bool cancelMovement = true)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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)
			if (!target.InCurrentLobby || !destination.InCurrentLobby)
			{
				throw new CommandException("Both the target and destination players must be in the lobby!");
			}
			if (!MyceliumNetwork.GetPlayerData<bool>(target.steamID, "chatCommandsInstalled"))
			{
				throw new CommandException("The target does not have chat commands installed!");
			}
			GameObject spawnedPlayer = target.SpawnedPlayer;
			if (!Object.op_Implicit((Object)(object)((spawnedPlayer != null) ? spawnedPlayer.GetComponent<FirstPersonController>() : null)))
			{
				throw new CommandException("The target player is not spawned!");
			}
			GameObject spawnedPlayer2 = destination.SpawnedPlayer;
			FirstPersonController val = ((spawnedPlayer2 != null) ? spawnedPlayer2.GetComponent<FirstPersonController>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new CommandException("The destination player is not spawned!");
			}
			MyceliumNetwork.RPCTarget(25u, "RPCTeleportPlayer", target.steamID, (ReliableType)1, new object[4]
			{
				((Component)val).transform.position,
				PlayerEulerAngles(val),
				includeRotation,
				cancelMovement
			});
		}

		[CustomRPC]
		private void RPCTeleportPlayer(Vector3 location, Vector3 rotation, bool includeRotation, bool cancelMovement)
		{
			//IL_0000: 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)
			TeleportLocalPlayer(location, includeRotation ? new Vector3?(rotation) : null, cancelMovement);
		}

		private static Vector3 PlayerEulerAngles(FirstPersonController player)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			float rotationX = player.rotationX;
			Quaternion rotation = ((Component)player).transform.rotation;
			return new Vector3(rotationX, ((Quaternion)(ref rotation)).eulerAngles.y, player.rotationZ);
		}

		private static void TeleportLocalPlayer(Vector3 location, Vector3? rotation = null, bool cancelMovement = true)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_003e: 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_0055: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00b1: 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_00bc: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			FirstPersonController localPlayer = Settings.Instance.localPlayer;
			((Component)localPlayer).transform.position = location;
			if (rotation.HasValue)
			{
				Vector3 valueOrDefault = rotation.GetValueOrDefault();
				((Component)localPlayer).transform.rotation = Quaternion.Euler(0f, valueOrDefault.y, 0f);
				localPlayer.rotationX = valueOrDefault.x;
				localPlayer.rotationZ = valueOrDefault.z;
			}
			if (cancelMovement)
			{
				localPlayer.moveDirection = Vector3.zero;
				localPlayer.verticalInput = 0f;
				localPlayer.horizontalInput = 0f;
				localPlayer.forceFactor = 0f;
				localPlayer.bstop = true;
				localPlayer.slopeSlideScript.slopeSlideMove = Vector3.zero;
				localPlayer.slopeSlideScript.steepSlopeSlideMove = Vector3.zero;
				localPlayer.objectCollisionMoveDirection = Vector3.zero;
				localPlayer.customForceScript.impact = Vector3.zero;
				localPlayer.characterController.SimpleMove(Vector3.zero);
			}
			localPlayer.PlaySoundServer(23);
		}
	}
	[CommandCategory("Utility")]
	public static class UtilityCommands
	{
		private static CommandFlags[] m_allFlags = (CommandFlags[])Enum.GetValues(typeof(CommandFlags));

		[Command("echo", "outputs its input", CommandFlags.None)]
		public static string Echo(string input)
		{
			return input;
		}

		[Command("eval", "evaluates its input as a command", CommandFlags.None)]
		public static void Eval(string input)
		{
			Evaluator.Instance.Evaluate(input);
		}

		[Command("repeat", "executes a command a specified number of times", CommandFlags.None)]
		public static void Repeat(string command, int n)
		{
			for (int i = 0; i < n; i++)
			{
				Evaluator.Instance.Evaluate(command);
			}
		}

		[Command("concat", "concatenates two strings", CommandFlags.None)]
		public static string Concat(string first, string second)
		{
			return first + second;
		}

		[Command("add", "adds the provided numbers", CommandFlags.None)]
		public static float Add(float first, float second)
		{
			return first + second;
		}

		[Command("subtract", "subtracts the second number from the first", CommandFlags.None)]
		public static float Subtract(float first, float second)
		{
			return first - second;
		}

		[Command("rsubtract", "subtracts the first number from the second", CommandFlags.None)]
		public static float RSubtract(float first, float second)
		{
			return second - first;
		}

		[Command("multiply", "multiplies the provided numbers", CommandFlags.None)]
		public static float Multiply(float first, float second)
		{
			return first * second;
		}

		[Command("divide", "divides the first number by the second", CommandFlags.None)]
		public static float Divide(float first, float second)
		{
			return first / second;
		}

		[Command("rdivide", "divides the second number by the first", CommandFlags.None)]
		public static float RDivide(float first, float second)
		{
			return second / first;
		}

		[Command("randint", "gets a random int in [min, max) (min inclusive, max exclusive)", CommandFlags.None)]
		public static int RandInt(int minInclusive, int maxExclusive)
		{
			return Random.Range(minInclusive, maxExclusive);
		}

		[Command("randfloat", "gets a random float in [min, max] (inclusive)", CommandFlags.None)]
		public static float RandFloat(float minInclusive, float maxInclusive)
		{
			return Random.Range(minInclusive, maxInclusive);
		}

		[Command("clear", "clears the chat", CommandFlags.None)]
		[CommandAliases(new string[] { "cls" })]
		public static void Clear()
		{
			ChatPatches.ClearChat();
		}

		[Command("say", "sends a message in chat", CommandFlags.None)]
		public static void Say(string message)
		{
			ChatPatches.SendChatMessage(FilterSystem.FilterString(message));
		}

		[Command("help", "prints command info", CommandFlags.None)]
		[CommandAliases(new string[] { "h" })]
		public static string Help(string commandOrCategoryName = "")
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (commandOrCategoryName != string.Empty)
			{
				if (CommandRegistry.TryGet(commandOrCategoryName, out var command))
				{
					stringBuilder.AppendHelpTextForCommand(command);
				}
				else
				{
					if (!CommandRegistry.CategoryExists(commandOrCategoryName))
					{
						throw new CommandException("No command or category with the name " + commandOrCategoryName + " found.");
					}
					Command[] array = CommandRegistry.Commands.Values.Where((Command c) => string.Equals(c.categoryName, commandOrCategoryName, StringComparison.OrdinalIgnoreCase)).Distinct().ToArray();
					if (array.Length == 0)
					{
						throw new CommandException("No command or category with the name " + commandOrCategoryName + " found.");
					}
					stringBuilder.AppendLine(HeaderText(array[0].categoryName)).AppendLine();
					foreach (Command item in array.OrderBy((Command c) => c.name))
					{
						stringBuilder.AppendHelpTextForCommand(item).AppendLine().AppendLine();
					}
				}
			}
			else
			{
				string text = "";
				foreach (Command item2 in (from c in CommandRegistry.Commands.Values
					orderby c.categoryName, c.name
					select c).Distinct())
				{
					if (item2.categoryName != text)
					{
						text = item2.categoryName;
						stringBuilder.AppendLine(HeaderText(item2.categoryName));
						stringBuilder.AppendLine();
					}
					stringBuilder.AppendHelpTextForCommand(item2);
					stringBuilder.AppendLine().AppendLine();
				}
			}
			return stringBuilder.ToString();
		}

		private static StringBuilder AppendHelpTextForCommand(this StringBuilder builder, Command command)
		{
			if (command.isOverriden)
			{
				builder.Append(SmallText("(overriden) "));
			}
			builder.AppendLine("<u>" + command.name + "</u>").AppendLine(command.description);
			builder.Append("aliases: [");
			if (command.aliases.Length == 0)
			{
				builder.Append("none");
			}
			for (int i = 0; i < command.aliases.Length; i++)
			{
				builder.Append(command.aliases[i]);
				if (i < command.aliases.Length - 1)
				{
					builder.Append(", ");
				}
			}
			builder.AppendLine("]");
			builder.Append("parameters: [");
			if (command.maxParameters == 0)
			{
				builder.Append("none");
			}
			for (int j = 0; j < command.maxParameters; j++)
			{
				ParameterInfo parameterInfo = command.parameterInfos[j];
				if (parameterInfo.HasDefaultValue)
				{
					builder.Append(SmallText("(optional) "));
				}
				Type parameterType = parameterInfo.ParameterType;
				string text = ((!parameterType.IsGenericType || parameterType.IsGenericTypeDefinition || !(parameterType.GetGenericTypeDefinition() == typeof(Nullable<>))) ? parameterType.Name : (Nullable.GetUnderlyingType(parameterType)?.Name ?? "unknown"));
				builder.Append(parameterInfo.Name).Append(": ").Append(text.ToLower());
				if (j < command.maxParameters - 1)
				{
					builder.Append(", ");
				}
			}
			builder.AppendLine("]");
			Enum[] array = (from Enum f in m_allFlags
				where command.flags.HasFlag(f) && !f.Equals(CommandFlags.None)
				select f).ToArray();
			if (array.Length != 0)
			{
				builder.Append("flags: [");
				for (int k = 0; k < array.Length; k++)
				{
					builder.Append(array[k]);
					if (k < array.Length - 1)
					{
						builder.Append(", ");
					}
				}
				builder.AppendLine("]");
			}
			Type returnType = command.method.ReturnType;
			builder.Append("returns: ").Append((returnType == typeof(void)) ? "none" : returnType.Name.ToLower());
			return builder;
		}

		private static string SmallText(string text)
		{
			return "<alpha=#AA><voffset=0.1em><size=65%>" + text + "</size></voffset><alpha=#FF>";
		}

		private static string HeaderText(string text)
		{
			return "<u><size=150%><#B4F6B7>" + text + "</color></size></u>";
		}
	}
	[CommandCategory("Settings")]
	public static class SettingsCommands
	{
		private static readonly FieldInfo fovSetting = AccessTools.Field(typeof(Settings), "normalFovValue");

		private static readonly FieldInfo brightnessSetting = AccessTools.Field(typeof(Settings), "brightness");

		private static readonly FieldInfo mouseSensitivitySetting = AccessTools.Field(typeof(Settings), "mouseSensitivity");

		private static readonly FieldInfo mouseAimSensitivitySetting = AccessTools.Field(typeof(Settings), "mouseAimSensitivity");

		private static readonly FieldInfo mouseAimScopeSensitivitySetting = AccessTools.Field(typeof(Settings), "mouseAimScopeSensitivity");

		private static float PseudoConvarFloat(float? value, Func<float> getter, Func<float, float> setter)
		{
			if (value.HasValue)
			{
				return setter(value.Value);
			}
			return getter();
		}

		private static int PseudoConvarInt(int? value, Func<int> getter, Func<int, int> setter)
		{
			if (value.HasValue)
			{
				return setter(value.Value);
			}
			return getter();
		}

		private static float PseudoConvarSetting(float? value, FieldInfo settingField, string settingName)
		{
			Settings instance = Settings.Instance;
			if (!value.HasValue)
			{
				return (float)settingField.GetValue(instance);
			}
			settingField.SetValue(instance, value.Value);
			PlayerPrefs.SetFloat(settingName, value.Value);
			PlayerPrefs.Save();
			return value.Value;
		}

		[Command("maxfps", "*temporarily* changes max fps", CommandFlags.Silent)]
		public static int MaxFps(int? fps = null)
		{
			return PseudoConvarInt(fps, () => Application.targetFrameRate, (int f) => Application.targetFrameRate = f);
		}

		[Command("fov", "changes fov", CommandFlags.Silent)]
		public static float Fov(float? fov = null)
		{
			return PseudoConvarSetting(fov, fovSetting, "fovValue");
		}

		[Command("gamma", "changes gamma (brightness)", CommandFlags.Silent)]
		public static float Gamma(float? gamma = null)
		{
			return PseudoConvarSetting(gamma, brightnessSetting, "brightness");
		}

		[Command("sensitivity", "changes sensitivity", CommandFlags.Silent)]
		public static float Sensitivity(float? sensitivity = null)
		{
			return PseudoConvarSetting(sensitivity, mouseSensitivitySetting, "mouseSensitivity");
		}

		[Command("aimsensitivity", "changes aiming sensitivity", CommandFlags.Silent)]
		public static float AimSensitivity(float? sensitivity = null)
		{
			return PseudoConvarSetting(sensitivity, mouseAimSensitivitySetting, "mouseAimSensitivity");
		}

		[Command("scopesensitivity", "changes scope sensitivity", CommandFlags.Silent)]
		public static float ScopeSensitivity(float? sensitivity = null)
		{
			return PseudoConvarSetting(sensitivity, mouseAimScopeSensitivitySetting, "mouseAimScopeSensitivity");
		}
	}
	internal static class WeaponLoader
	{
		private static Dictionary<string, Weapon> m_weaponPrefabs = new Dictionary<string, Weapon>();

		private static Dictionary<string, PhysicsProp> m_propPrefabs = new Dictionary<string, PhysicsProp>();

		public static void Init()
		{
			Weapon[] array = Resources.LoadAll<Weapon>("RandomWeapons");
			foreach (Weapon val in array)
			{
				string key = ((Object)val).name.ToUpper().Replace(" ", "");
				string key2 = ((Component)val).GetComponent<ItemBehaviour>().weaponName.ToUpper().Replace(" ", "");
				m_weaponPrefabs.TryAdd(key, val);
				m_weaponPrefabs.TryAdd(key2, val);
			}
			PrefabObjects spawnablePrefabs = InstanceFinder.NetworkManager.SpawnablePrefabs;
			foreach (PhysicsProp item in from nob in ((SinglePrefabObjects)((spawnablePrefabs is DefaultPrefabObjects) ? spawnablePrefabs : null)).Prefabs
				select ((Component)nob).GetComponent<PhysicsProp>() into x
				where Object.op_Implicit((Object)(object)x)
				select x)
			{
				string key3 = ((Object)item).name.ToUpper().Replace(" ", "");
				string key4 = ((InteractEnvironment)item).popupText.ToUpper().Replace(" ", "");
				m_propPrefabs.TryAdd(key3, item);
				m_propPrefabs.TryAdd(key4, item);
			}
		}

		public static bool TryGetProp(string name, out PhysicsProp prefab)
		{
			string key = name.ToUpper().Replace(" ", "");
			return m_propPrefabs.TryGetValue(key, out prefab);
		}

		public static bool TryGetWeapon(string name, out Weapon prefab)
		{
			string key = name.ToUpper().Replace(" ", "");
			return m_weaponPrefabs.TryGetValue(key, out prefab);
		}

		public static Weapon RandomWeapon()
		{
			return m_weaponPrefabs.RandomValues().Take(1).First();
		}

		public static Weapon[] RandomWeapons(int count)
		{
			return m_weaponPrefabs.RandomValues().Take(count).ToArray();
		}
	}
}
namespace ChatCommands.Attributes
{
	[AttributeUsage(AttributeTargets.Method)]
	public class CommandAliasesAttribute : Attribute
	{
		public readonly string[] aliases;

		public CommandAliasesAttribute(params string[] aliases)
		{
			this.aliases = aliases;
			base..ctor();
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class CommandAttribute : Attribute
	{
		public readonly string name;

		public readonly string description;

		public readonly CommandFlags flags;

		public CommandAttribute(string name, string description, CommandFlags flags = CommandFlags.None)
		{
			this.name = name;
			this.description = description;
			this.flags = flags;
			base..ctor();
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class CommandCategoryAttribute : Attribute
	{
		public readonly string name;

		public CommandCategoryAttribute(string name)
		{
			this.name = name;
			base..ctor();
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class CommandOverrideAttribute : Attribute
	{
		public readonly int priority;

		public CommandOverrideAttribute(int priority = int.MaxValue)
		{
			this.priority = priority;
			base..ctor();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}