Decompiled source of VampireCommandFramework v0.11.0

VampireCommandFramework.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
using ProjectM;
using ProjectM.Network;
using SemanticVersioning;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using VCF.Core.Basics;
using VampireCommandFramework;
using VampireCommandFramework.Basics;
using VampireCommandFramework.Breadstone;
using VampireCommandFramework.Common;
using VampireCommandFramework.Framework;
using VampireCommandFramework.Registry;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("deca")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Framework for commands in V Rising")]
[assembly: AssemblyFileVersion("0.11.0.0")]
[assembly: AssemblyInformationalVersion("0.11.0+6.Branch.main.Sha.49faa2ed38b7c35e0a05ce0a7f973261c7d58620")]
[assembly: AssemblyProduct("VampireCommandFramework")]
[assembly: AssemblyTitle("VampireCommandFramework")]
[assembly: InternalsVisibleTo("VCF.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.11.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace VampireCommandFramework
{
	public class ChatCommandContext : ICommandContext
	{
		private static int maxMessageLength = 509;

		public VChatEvent Event { get; }

		public User User => Event.User;

		public IServiceProvider Services { get; }

		public string Name
		{
			get
			{
				//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)
				User user = User;
				return ((object)(FixedString64Bytes)(ref user.CharacterName)).ToString();
			}
		}

		public bool IsAdmin => User.IsAdmin;

		public ChatCommandContext(VChatEvent e)
		{
			Event = e;
		}

		public void Reply(string v)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (v.Length > maxMessageLength)
			{
				v = v.Substring(0, maxMessageLength);
			}
			ChatMessageQueue.Send(User, v);
		}

		public CommandException Error(string LogMessage)
		{
			return new CommandException(LogMessage);
		}
	}
	public static class Color
	{
		public static string Red = "red";

		public static string Primary = "#d25";

		public static string White = "#eee";

		public static string LightGrey = "#bbf";

		public static string Yellow = "#dd0";

		public static string DarkGreen = "#0c0";

		public static string Green = "#4c4";

		public static string Command = "#4ED";

		public static string Beige = "#fed";

		public static string Gold = "#eb0";

		public static string Lavender = "#c5d";

		public static string Pink = "#faf";

		public static string Periwinkle = "#52d";

		public static string Teal = "#3ac";

		public static string LightRed = "#f45";

		public static string LightPurple = "#84c";

		public static string Lilac = "#b9f";

		public static string LightPink = "#EED";

		public static string SoftBGrey = "#eef";

		public static string AdminUsername = "#afa";

		public static string ClanName = "#59e";

		public static string LightBlood = "#f44";

		public static string Blood = "#c24";

		public static string LightChaos = "#faf";

		public static string Chaos = "#d5e";

		public static string LightUnholy = "#bd3";

		public static string Unholy = "#4c0";

		public static string LightIllusion = "#bfd";

		public static string Illusion = "#3db";

		public static string LightFrost = "#aef";

		public static string Frost = "#09f";

		public static string LightStorm = "#fe7";

		public static string Storm = "#ff5";

		public static string Discord = "#78f";

		public static string Global = "#8cf";

		public static string ClassicUsername = "#876";
	}
	public abstract class CommandArgumentConverter<T> : CommandArgumentConverter<T, ICommandContext>
	{
	}
	public abstract class CommandArgumentConverter<T, C> where C : ICommandContext
	{
		public abstract T Parse(C ctx, string input);
	}
	[AttributeUsage(AttributeTargets.Method)]
	public sealed class CommandAttribute : Attribute
	{
		public string Name { get; }

		public string ShortHand { get; }

		public string Usage { get; }

		public string Description { get; }

		public string Id { get; }

		public bool AdminOnly { get; }

		public CommandAttribute(string name, string shortHand = null, string usage = null, string description = null, string id = null, bool adminOnly = false)
		{
			Name = name;
			ShortHand = shortHand;
			Usage = usage;
			Description = description;
			Id = id ?? Name.Replace(" ", "-");
			AdminOnly = adminOnly;
		}
	}
	[Serializable]
	public class CommandException : Exception
	{
		public CommandException()
		{
		}

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

		public CommandException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected CommandException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public sealed class CommandGroupAttribute : Attribute
	{
		public string Name { get; }

		public string ShortHand { get; }

		public CommandGroupAttribute(string name, string shortHand = null)
		{
			Name = name;
			ShortHand = shortHand;
		}
	}
	public abstract class CommandMiddleware
	{
		public virtual bool CanExecute(ICommandContext ctx, CommandAttribute attribute, MethodInfo method)
		{
			return true;
		}

		public virtual void BeforeExecute(ICommandContext ctx, CommandAttribute attribute, MethodInfo method)
		{
		}

		public virtual void AfterExecute(ICommandContext ctx, CommandAttribute attribute, MethodInfo method)
		{
		}
	}
	public enum CommandResult
	{
		Unmatched,
		UsageError,
		CommandError,
		InternalError,
		Denied,
		Success
	}
	public static class Format
	{
		public enum FormatMode
		{
			GameChat,
			None
		}

		public static FormatMode Mode { get; set; }

		public static string B(string input)
		{
			return input.Bold();
		}

		public static string Bold(this string input)
		{
			return (Mode == FormatMode.GameChat) ? ("<b>" + input + "</b>") : input;
		}

		public static string I(string input)
		{
			return input.Italic();
		}

		public static string Italic(this string input)
		{
			return (Mode == FormatMode.GameChat) ? ("<i>" + input + "</i>") : input;
		}

		public static string Underline(this string input)
		{
			return (Mode == FormatMode.GameChat) ? ("<u>" + input + "</u>") : input;
		}

		public static string Color(this string input, string color)
		{
			return (Mode == FormatMode.GameChat) ? $"<color={color}>{input}</color>" : input;
		}

		public static string Size(this string input, int size)
		{
			return (Mode == FormatMode.GameChat) ? $"<size={size}>{input}</size>" : input;
		}

		public static string Small(this string input)
		{
			return input.Size(10);
		}

		public static string Normal(this string input)
		{
			return input.Size(16);
		}

		public static string Medium(this string input)
		{
			return input.Size(20);
		}

		public static string Large(this string input)
		{
			return input.Size(24);
		}
	}
	public interface ICommandContext
	{
		IServiceProvider Services { get; }

		string Name { get; }

		bool IsAdmin { get; }

		CommandException Error(string LogMessage);

		void Reply(string v);
	}
	public interface IConverterUsage
	{
		string Usage { get; }
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
	public sealed class RemainderAttribute : Attribute
	{
	}
	[BepInPlugin("gg.deca.VampireCommandFramework", "VampireCommandFramework", "0.11.0")]
	internal class Plugin : BasePlugin
	{
		private Harmony _harmony;

		public override void Load()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			Log.Instance = ((BasePlugin)this).Log;
			if (!VWorld.IsServer)
			{
				((BasePlugin)this).Log.LogMessage((object)"Note: Vampire Command Framework is loading on the client but only adds functionality on the server at this time, seeing this message is not a problem or bug.");
				return;
			}
			_harmony = new Harmony("gg.deca.VampireCommandFramework");
			_harmony.PatchAll();
			ChatDrainPatch.Install();
			CommandRegistry.RegisterCommandType(typeof(HelpCommands));
			CommandRegistry.RegisterCommandType(typeof(BepInExConfigCommands));
			CommandRegistry.RegisterCommandType(typeof(RepeatCommands));
			CommandRegistry.RegisterCommandType(typeof(VersionCommands));
			((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue("gg.deca.VampireCommandFramework", out var value);
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExMessageLogInterpolatedStringHandler val = new BepInExMessageLogInterpolatedStringHandler(12, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("VCF Loaded: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Version>((value != null) ? value.Metadata.Version : null);
			}
			log.LogMessage(val);
		}

		public override bool Unload()
		{
			_harmony.UnpatchSelf();
			return true;
		}
	}
	public static class CommandRegistry
	{
		internal const string DEFAULT_PREFIX = ".";

		internal static CommandCache _cache = new CommandCache();

		internal static Dictionary<Type, (object instance, MethodInfo tryParse, Type contextType)> _converters = new Dictionary<Type, (object, MethodInfo, Type)>();

		private static List<CommandMiddleware> DEFAULT_MIDDLEWARES = new List<CommandMiddleware>
		{
			new BasicAdminCheck()
		};

		private static Dictionary<string, (string input, List<(CommandMetadata Command, object[] Args, string Error)> commands)> _pendingCommands = new Dictionary<string, (string, List<(CommandMetadata, object[], string)>)>();

		public static List<CommandMiddleware> Middlewares { get; } = new List<CommandMiddleware>
		{
			new BasicAdminCheck()
		};


		internal static Dictionary<string, Dictionary<CommandMetadata, List<string>>> AssemblyCommandMap { get; } = new Dictionary<string, Dictionary<CommandMetadata, List<string>>>();


		internal static void Reset()
		{
			Middlewares.Clear();
			Middlewares.AddRange(DEFAULT_MIDDLEWARES);
			AssemblyCommandMap.Clear();
			_converters.Clear();
			_cache = new CommandCache();
			CommandHistory.Reset();
			_pendingCommands.Clear();
		}

		internal static ParsedCommandInput ParseInput(string input)
		{
			string text = input.Substring(".".Length);
			int num = text.IndexOf(' ');
			if (num > 0)
			{
				string potentialAssemblyName = text.Substring(0, num);
				if (AssemblyCommandMap.Keys.Any((string an) => an.Equals(potentialAssemblyName, StringComparison.OrdinalIgnoreCase)))
				{
					string text2 = text.Substring(num + 1);
					string text3 = "." + text2;
					CacheResult commandFromAssembly = _cache.GetCommandFromAssembly(text3, potentialAssemblyName);
					if (commandFromAssembly != null && commandFromAssembly.IsMatched)
					{
						return new ParsedCommandInput(potentialAssemblyName, text3, text2);
					}
				}
			}
			return new ParsedCommandInput(null, input, text);
		}

		internal static CacheResult GetCommandFromCache(string input, string assemblyName = null)
		{
			if (assemblyName != null)
			{
				return _cache.GetCommandFromAssembly(input, assemblyName);
			}
			return _cache.GetCommand(input);
		}

		internal static bool CanCommandExecute(ICommandContext ctx, CommandMetadata command)
		{
			foreach (CommandMiddleware middleware in Middlewares)
			{
				try
				{
					if (!middleware.CanExecute(ctx, command.Attribute, command.Method))
					{
						return false;
					}
				}
				catch (Exception value)
				{
					Log.Error($"Error executing {middleware.GetType().Name.Color(Color.Gold)} {value}");
					return false;
				}
			}
			return true;
		}

		internal static bool IsRemainderParameter(ParameterInfo p)
		{
			return p.ParameterType == typeof(string) && p.IsDefined(typeof(RemainderAttribute), inherit: false);
		}

		internal static bool HasRemainderParameter(CommandMetadata command)
		{
			if (command.Parameters.Length == 0)
			{
				return false;
			}
			return IsRemainderParameter(command.Parameters[command.Parameters.Length - 1]);
		}

		internal static IEnumerable<string> FindCloseMatches(ICommandContext ctx, string input)
		{
			if (string.IsNullOrWhiteSpace(input))
			{
				return Enumerable.Empty<string>();
			}
			string normalizedInput = ParseInput(input).AfterPrefixAndAssembly.ToLowerInvariant();
			int maxDistance = Math.Max(3, (int)Math.Ceiling((double)normalizedInput.Length * 0.5));
			List<CommandMetadata> source = AssemblyCommandMap.SelectMany((KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> a) => a.Value.Keys).ToList();
			return from x in (from x in source.Where((CommandMetadata c) => CanCommandExecute(ctx, c)).SelectMany(delegate(CommandMetadata cmd)
					{
						string[] source2 = ((cmd.GroupAttribute != null) ? ((cmd.GroupAttribute.ShortHand != null) ? new string[2]
						{
							cmd.GroupAttribute.Name + " ",
							cmd.GroupAttribute.ShortHand + " "
						} : new string[1] { cmd.GroupAttribute.Name + " " }) : new string[1] { "" });
						string[] commandNames = ((cmd.Attribute.ShortHand != null) ? new string[2]
						{
							cmd.Attribute.Name,
							cmd.Attribute.ShortHand
						} : new string[1] { cmd.Attribute.Name });
						return source2.SelectMany((string @group) => commandNames.Select((string name) => new
						{
							FullName = (@group + name).ToLowerInvariant(),
							Command = cmd
						}));
					}).Select(cmdInfo =>
					{
						float distance = DamerauLevenshteinDistance(normalizedInput, cmdInfo.FullName);
						int maxDistance2 = Math.Max(maxDistance, (int)Math.Ceiling((double)normalizedInput.Length * 0.5));
						return new
						{
							Command = cmdInfo.FullName,
							Distance = distance,
							MaxDistance = maxDistance2
						};
					})
					where x.Distance <= (float)x.MaxDistance
					orderby x.Distance
					select x).DistinctBy(x => x.Command).Take(3)
				select "." + x.Command;
		}

		private static float DamerauLevenshteinDistance(string s, string t)
		{
			if (string.IsNullOrEmpty(s))
			{
				return (!string.IsNullOrEmpty(t)) ? t.Length : 0;
			}
			if (string.IsNullOrEmpty(t))
			{
				return s.Length;
			}
			float[,] array = new float[s.Length + 1, t.Length + 1];
			for (int i = 0; i <= s.Length; i++)
			{
				array[i, 0] = i;
			}
			for (int j = 0; j <= t.Length; j++)
			{
				array[0, j] = j;
			}
			for (int k = 1; k <= s.Length; k++)
			{
				for (int l = 1; l <= t.Length; l++)
				{
					int num = ((s[k - 1] != t[l - 1]) ? 1 : 0);
					array[k, l] = Math.Min(Math.Min(array[k - 1, l] + 1f, array[k, l - 1] + 1f), array[k - 1, l - 1] + 1.5f * (float)num);
					if (k > 1 && l > 1 && s[k - 1] == t[l - 2] && s[k - 2] == t[l - 1])
					{
						array[k, l] = Math.Min(array[k, l], array[k - 2, l - 2] + (float)num);
					}
				}
			}
			return array[s.Length, t.Length];
		}

		private static void HandleBeforeExecute(ICommandContext ctx, CommandMetadata command)
		{
			Middlewares.ForEach(delegate(CommandMiddleware m)
			{
				m.BeforeExecute(ctx, command.Attribute, command.Method);
			});
		}

		private static void HandleAfterExecute(ICommandContext ctx, CommandMetadata command)
		{
			Middlewares.ForEach(delegate(CommandMiddleware m)
			{
				m.AfterExecute(ctx, command.Attribute, command.Method);
			});
		}

		public static CommandResult Handle(ICommandContext ctx, string input)
		{
			CommandHistory.EnsureHistoryLoaded(ctx);
			if (input.StartsWith(".") && input.Length > 1)
			{
				string s = input.Substring(1);
				if (int.TryParse(s, out var result) && result > 0)
				{
					return HandleCommandSelection(ctx, result);
				}
			}
			if (!input.StartsWith("."))
			{
				return CommandResult.Unmatched;
			}
			if (input.Trim().StartsWith(".!"))
			{
				return CommandHistory.HandleHistoryCommand(ctx, input.Trim(), Handle, ExecuteCommandWithArgs);
			}
			ParsedCommandInput parsedCommandInput = ParseInput(input);
			CacheResult cacheResult = null;
			if (parsedCommandInput.HasAssembly)
			{
				cacheResult = _cache.GetCommandFromAssembly(parsedCommandInput.CommandInput, parsedCommandInput.AssemblyName);
			}
			if (cacheResult == null || !cacheResult.IsMatched)
			{
				cacheResult = _cache.GetCommand(input);
			}
			IEnumerable<(CommandMetadata, string[])> commands = cacheResult.Commands;
			if (!cacheResult.IsMatched)
			{
				if (!cacheResult.HasPartial)
				{
					return CommandResult.Unmatched;
				}
				foreach (CommandMetadata partialMatch in cacheResult.PartialMatches)
				{
					ctx.SysReply(HelpCommands.GetShortHelp(partialMatch));
				}
				return CommandResult.UsageError;
			}
			if (commands.Count() != 1)
			{
				List<(CommandMetadata, object[], string)> list = new List<(CommandMetadata, object[], string)>();
				List<(CommandMetadata, string)> list2 = new List<(CommandMetadata, string)>();
				List<CommandMetadata> list3 = new List<CommandMetadata>();
				foreach (var (commandMetadata, args) in commands)
				{
					if (!CanCommandExecute(ctx, commandMetadata))
					{
						list3.Add(commandMetadata);
						continue;
					}
					var (flag, item, item2) = TryConvertParameters(ctx, commandMetadata, args, parsedCommandInput.CommandInput);
					if (flag)
					{
						list.Add((commandMetadata, item, null));
					}
					else
					{
						list2.Add((commandMetadata, item2));
					}
				}
				StringBuilder stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler;
				if (list.Count == 0)
				{
					if (list2.Count == 0 && list3.Count > 0)
					{
						ctx.SysReply("[denied]".Color(Color.Red) + " " + list3[0].Attribute.Name.ToString().Color(Color.Gold));
						return CommandResult.Denied;
					}
					StringBuilder stringBuilder = new StringBuilder();
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder3 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(62, 1, stringBuilder2);
					handler.AppendFormatted("[error]".Color(Color.Red));
					handler.AppendLiteral(" Failed to execute command due to parameter conversion errors:");
					stringBuilder3.AppendLine(ref handler);
					foreach (var item6 in list2)
					{
						CommandMetadata item3 = item6.Item1;
						string item4 = item6.Item2;
						string assemblyName = item3.AssemblyName;
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder4 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(9, 3, stringBuilder2);
						handler.AppendLiteral("  - ");
						handler.AppendFormatted(item3.Attribute.Name);
						handler.AppendLiteral(" (");
						handler.AppendFormatted(assemblyName);
						handler.AppendLiteral("): ");
						handler.AppendFormatted(item4);
						stringBuilder4.AppendLine(ref handler);
					}
					ctx.SysPaginatedReply(stringBuilder);
					return CommandResult.UsageError;
				}
				if (list.Count == 1)
				{
					var (command, array, _) = list[0];
					CommandHistory.AddToHistory(ctx, input, command, array);
					return ExecuteCommandWithArgs(ctx, command, array);
				}
				string name = ctx.Name;
				_pendingCommands[name] = (input, list);
				StringBuilder stringBuilder5 = new StringBuilder();
				stringBuilder2 = stringBuilder5;
				StringBuilder stringBuilder6 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(58, 1, stringBuilder2);
				handler.AppendLiteral("Multiple commands match this input. Select one by typing ");
				handler.AppendFormatted(Format.B(".<#>").Color(Color.Command));
				handler.AppendLiteral(":");
				stringBuilder6.AppendLine(ref handler);
				for (int i = 0; i < list.Count; i++)
				{
					CommandMetadata item5 = list[i].Item1;
					string assemblyName2 = item5.AssemblyName;
					string description = item5.Attribute.Description;
					stringBuilder2 = stringBuilder5;
					StringBuilder stringBuilder7 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(8, 4, stringBuilder2);
					handler.AppendLiteral(" ");
					handler.AppendFormatted(("." + (i + 1)).Color(Color.Command));
					handler.AppendLiteral(" - ");
					handler.AppendFormatted(assemblyName2.Bold().Color(Color.Primary));
					handler.AppendLiteral(" - ");
					handler.AppendFormatted(Format.B(item5.Attribute.Name));
					handler.AppendLiteral(" ");
					handler.AppendFormatted(item5.Attribute.Description);
					stringBuilder7.AppendLine(ref handler);
					stringBuilder5.AppendLine("   " + HelpCommands.GetShortHelp(item5));
				}
				ctx.SysPaginatedReply(stringBuilder5);
				return CommandResult.Success;
			}
			var (command2, args2) = commands.First();
			return ExecuteCommand(ctx, command2, args2, parsedCommandInput.CommandInput);
		}

		private static CommandResult HandleCommandSelection(ICommandContext ctx, int selectedIndex)
		{
			string name = ctx.Name;
			if (!_pendingCommands.TryGetValue(name, out (string, List<(CommandMetadata, object[], string)>) value) || value.Item2.Count == 0)
			{
				ctx.SysReply("[error]".Color(Color.Red) + " No command selection is pending.");
				return CommandResult.CommandError;
			}
			if (selectedIndex < 1 || selectedIndex > value.Item2.Count)
			{
				ctx.SysReply($"{"[error]".Color(Color.Red)} Invalid selection. Please select a number between {"1".Color(Color.Gold)} and {value.Item2.Count.ToString().Color(Color.Gold)}.");
				return CommandResult.UsageError;
			}
			var (command, array, _) = value.Item2[selectedIndex - 1];
			CommandHistory.AddToHistory(ctx, value.Item1, command, array);
			CommandResult result = ExecuteCommandWithArgs(ctx, command, array);
			_pendingCommands.Remove(name);
			return result;
		}

		internal static (bool Success, object[] Args, string Error) TryConvertParameters(ICommandContext ctx, CommandMetadata command, string[] args, string originalInput = null)
		{
			int num = ((args != null) ? args.Length : 0);
			int num2 = command.Parameters.Length;
			object[] array = new object[num2 + 1];
			array[0] = ctx;
			bool flag = HasRemainderParameter(command);
			if (num2 == 0 && num == 0)
			{
				return (true, array, null);
			}
			if (flag)
			{
				return TryConvertParametersWithRemainder(ctx, command, args, originalInput, array);
			}
			if (num > num2)
			{
				return (false, null, "Too many parameters: expected " + num2.ToString().Color(Color.Gold) + ", got " + num.ToString().Color(Color.Gold));
			}
			if (num < num2)
			{
				IEnumerable<ParameterInfo> source = command.Parameters.Skip(num);
				if (!source.All((ParameterInfo p) => p.HasDefaultValue))
				{
					return (false, null, "Missing required parameters: expected " + num2.ToString().Color(Color.Gold) + ", got " + num.ToString().Color(Color.Gold));
				}
				for (int i = num; i < num2; i++)
				{
					array[i + 1] = command.Parameters[i].DefaultValue;
				}
			}
			for (int j = 0; j < Math.Min(num, num2); j++)
			{
				ParameterInfo param = command.Parameters[j];
				string arg = args[j];
				var (flag2, obj, item) = TryConvertSingleParameter(ctx, param, arg, j);
				if (!flag2)
				{
					return (false, null, item);
				}
				array[j + 1] = obj;
			}
			return (true, array, null);
		}

		private static (bool Success, object[] Args, string Error) TryConvertParametersWithRemainder(ICommandContext ctx, CommandMetadata command, string[] args, string originalInput, object[] commandArgs)
		{
			int num = ((args != null) ? args.Length : 0);
			int num2 = command.Parameters.Length;
			int num3 = num2 - 1;
			int num4 = 0;
			for (int i = 0; i < num3; i++)
			{
				if (!command.Parameters[i].HasDefaultValue)
				{
					num4++;
				}
			}
			if (num < num4)
			{
				return (false, null, "Missing required parameters: expected at least " + num4.ToString().Color(Color.Gold) + ", got " + num.ToString().Color(Color.Gold));
			}
			int num5 = Math.Min(num, num3);
			for (int num6 = num5; num6 >= num4; num6--)
			{
				var (flag, text) = TryConvertWithSplitPoint(ctx, command, args, originalInput, commandArgs, num6);
				if (flag)
				{
					return (true, commandArgs, null);
				}
				if ((text == null || !text.Contains("Parameter") || num6 <= num4) && num6 == num4)
				{
					return (false, null, text);
				}
			}
			return (false, null, "Failed to parse parameters");
		}

		private static (bool Success, string Error) TryConvertWithSplitPoint(ICommandContext ctx, CommandMetadata command, string[] args, string originalInput, object[] commandArgs, int splitPoint)
		{
			int num = command.Parameters.Length;
			int num2 = num - 1;
			for (int i = 0; i < splitPoint; i++)
			{
				ParameterInfo param = command.Parameters[i];
				string arg = args[i];
				var (flag, obj, item) = TryConvertSingleParameter(ctx, param, arg, i);
				if (!flag)
				{
					return (false, item);
				}
				commandArgs[i + 1] = obj;
			}
			for (int j = splitPoint; j < num2; j++)
			{
				ParameterInfo parameterInfo = command.Parameters[j];
				if (parameterInfo.HasDefaultValue)
				{
					commandArgs[j + 1] = parameterInfo.DefaultValue;
					continue;
				}
				return (false, $"Parameter {j + 1} ({parameterInfo.Name.ToString().Color(Color.Gold)}) is required but no value provided");
			}
			if (!string.IsNullOrEmpty(originalInput))
			{
				commandArgs[num2 + 1] = ExtractRemainderFromOriginalInput(originalInput, command, num2, splitPoint);
			}
			else
			{
				string[] value = args.Skip(splitPoint).ToArray();
				commandArgs[num2 + 1] = string.Join(" ", value);
			}
			return (true, null);
		}

		private static (bool Success, object ConvertedValue, string Error) TryConvertSingleParameter(ICommandContext ctx, ParameterInfo param, string arg, int paramIndex)
		{
			try
			{
				if (!_converters.TryGetValue(param.ParameterType, out (object, MethodInfo, Type) value))
				{
					TypeConverter converter = TypeDescriptor.GetConverter(param.ParameterType);
					try
					{
						object item = converter.ConvertFromInvariantString(arg);
						if (param.ParameterType.IsEnum)
						{
							bool flag = false;
							if (int.TryParse(arg, out var result) && !Enum.IsDefined(param.ParameterType, result))
							{
								return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): Invalid enum value '{arg.ToString().Color(Color.Gold)}' for {param.ParameterType.Name.ToString().Color(Color.Gold)}");
							}
						}
						return (true, item, null);
					}
					catch (Exception ex)
					{
						return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): {ex.Message}");
					}
				}
				var (obj, methodInfo, type) = value;
				if (!type.IsAssignableFrom(ctx.GetType()))
				{
					return (false, null, "INTERNAL_ERROR:Converter type " + type.Name.ToString().Color(Color.Gold) + " is not assignable from " + ctx.GetType().Name.ToString().Color(Color.Gold));
				}
				object[] parameters = new object[2] { ctx, arg };
				try
				{
					object item2 = methodInfo.Invoke(obj, parameters);
					return (true, item2, null);
				}
				catch (TargetInvocationException ex2)
				{
					if (ex2.InnerException is CommandException ex3)
					{
						return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): {ex3.Message}");
					}
					return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): Unexpected error converting parameter");
				}
				catch (Exception)
				{
					return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): Unexpected error converting parameter");
				}
			}
			catch (Exception ex5)
			{
				return (false, null, $"Parameter {paramIndex + 1} ({param.Name.ToString().Color(Color.Gold)}): Unexpected error: {ex5.Message}");
			}
		}

		private static string ExtractRemainderFromOriginalInput(string originalInput, CommandMetadata command, int remainderParameterIndex, int splitPoint = -1)
		{
			string text = originalInput.Substring(".".Length);
			int num = 0;
			if (command.GroupAttribute != null)
			{
				string name = command.GroupAttribute.Name;
				string shortHand = command.GroupAttribute.ShortHand;
				num = ((shortHand == null || !text.StartsWith(shortHand + " ", StringComparison.OrdinalIgnoreCase)) ? (num + name.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length) : (num + shortHand.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length));
			}
			string name2 = command.Attribute.Name;
			string shortHand2 = command.Attribute.ShortHand;
			if (shortHand2 != null)
			{
				int i = 0;
				for (int j = 0; j < num; j++)
				{
					for (; i < text.Length && text[i] != ' '; i++)
					{
					}
					for (; i < text.Length && text[i] == ' '; i++)
					{
					}
				}
				string text2 = text.Substring(i);
				num = ((!text2.StartsWith(shortHand2 + " ", StringComparison.OrdinalIgnoreCase) && !text2.Equals(shortHand2, StringComparison.OrdinalIgnoreCase)) ? (num + name2.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length) : (num + shortHand2.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length));
			}
			else
			{
				num += name2.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
			}
			int k = 0;
			for (int l = 0; l < num; l++)
			{
				for (; k < text.Length && text[k] != ' '; k++)
				{
				}
				for (; k < text.Length && text[k] == ' '; k++)
				{
				}
			}
			if (k >= text.Length)
			{
				return "";
			}
			string text3 = text.Substring(k);
			if (remainderParameterIndex == 0)
			{
				return text3;
			}
			int num2 = ((splitPoint >= 0) ? splitPoint : remainderParameterIndex);
			int num3 = 0;
			int m = 0;
			bool flag = false;
			while (m < text3.Length && num3 < num2)
			{
				char c = text3[m];
				if (c == '\\' && m + 1 < text3.Length && text3[m + 1] == '"')
				{
					m += 2;
					continue;
				}
				switch (c)
				{
				case '"':
					flag = !flag;
					break;
				case ' ':
					if (!flag)
					{
						for (; m < text3.Length && text3[m] == ' '; m++)
						{
						}
						num3++;
						continue;
					}
					break;
				}
				m++;
			}
			if (m < text3.Length)
			{
				return text3.Substring(m);
			}
			return "";
		}

		private static CommandResult ExecuteCommand(ICommandContext ctx, CommandMetadata command, string[] args, string input)
		{
			if (!command.ContextType.IsAssignableFrom(ctx?.GetType()))
			{
				Log.Warning($"Matched [{command.Attribute.Name.ToString().Color(Color.Gold)}] but can not assign {command.ContextType.Name.ToString().Color(Color.Gold)} from {ctx?.GetType().Name.ToString().Color(Color.Gold)}");
				return CommandResult.InternalError;
			}
			var (flag, array, text) = TryConvertParameters(ctx, command, args, input);
			if (!flag)
			{
				if (text != null && text.StartsWith("INTERNAL_ERROR:"))
				{
					string s = text.Substring("INTERNAL_ERROR:".Length);
					Log.Warning(s);
					ctx.InternalError();
					return CommandResult.InternalError;
				}
				ctx.SysReply("[error]".Color(Color.Red) + " " + text);
				return CommandResult.UsageError;
			}
			CommandHistory.AddToHistory(ctx, input, command, array);
			return ExecuteCommandWithArgs(ctx, command, array);
		}

		private static CommandResult ExecuteCommandWithArgs(ICommandContext ctx, CommandMetadata command, object[] commandArgs)
		{
			if (!command.ContextType.IsAssignableFrom(ctx?.GetType()))
			{
				Log.Warning($"Matched [{command.Attribute.Name.ToString().Color(Color.Gold)}] but can not assign {command.ContextType.Name.ToString().Color(Color.Gold)} from {ctx?.GetType().Name.ToString().Color(Color.Gold)}");
				return CommandResult.InternalError;
			}
			if (command.Constructor != null && !command.ConstructorType.IsAssignableFrom(ctx?.GetType()))
			{
				Log.Warning($"Matched [{command.Attribute.Name.ToString().Color(Color.Gold)}] but can not assign {command.ConstructorType.Name.ToString().Color(Color.Gold)} from {ctx?.GetType().Name.ToString().Color(Color.Gold)}");
				ctx.InternalError();
				return CommandResult.InternalError;
			}
			object obj = null;
			if (!command.Method.IsStatic && (!command.Method.DeclaringType.IsAbstract || !command.Method.DeclaringType.IsSealed))
			{
				try
				{
					object? obj2;
					if (!(command.Constructor == null))
					{
						ConstructorInfo constructor = command.Constructor;
						object[] parameters = new ICommandContext[1] { ctx };
						obj2 = constructor.Invoke(parameters);
					}
					else
					{
						obj2 = Activator.CreateInstance(command.Method.DeclaringType);
					}
					obj = obj2;
				}
				catch (TargetInvocationException ex)
				{
					if (ex.InnerException is CommandException ex2)
					{
						ctx.SysReply(ex2.Message);
					}
					else
					{
						ctx.InternalError();
					}
					return CommandResult.InternalError;
				}
			}
			if (!CanCommandExecute(ctx, command))
			{
				ctx.SysReply("[denied]".Color(Color.Red) + " " + command.Attribute.Name.ToString().Color(Color.Gold));
				return CommandResult.Denied;
			}
			HandleBeforeExecute(ctx, command);
			CommandException ex4 = default(CommandException);
			try
			{
				command.Method.Invoke(obj, commandArgs);
			}
			catch (TargetInvocationException ex3) when (((Func<bool>)delegate
			{
				// Could not convert BlockContainer to single expression
				ex4 = ex3.InnerException as CommandException;
				return ex4 != null;
			}).Invoke())
			{
				ctx.SysReply("[error]".Color(Color.Red) + " " + ex4.Message);
				return CommandResult.CommandError;
			}
			catch (Exception value)
			{
				Log.Warning($"Hit unexpected exception executing command {command.Attribute.Id.ToString().Color(Color.Gold)}\n: {value}");
				ctx.InternalError();
				return CommandResult.InternalError;
			}
			HandleAfterExecute(ctx, command);
			return CommandResult.Success;
		}

		public static void UnregisterConverter(Type converter)
		{
			if (IsGenericConverterContext(converter) || IsSpecificConverterContext(converter))
			{
				Type[] genericTypeArguments = converter.BaseType.GenericTypeArguments;
				Type type = genericTypeArguments.FirstOrDefault();
				if (type == null)
				{
					Log.Warning("Could not resolve converter type " + converter.Name.ToString().Color(Color.Gold));
				}
				else if (_converters.ContainsKey(type))
				{
					_converters.Remove(type);
					Log.Info("Unregistered converter " + converter.Name);
				}
				else
				{
					Log.Warning("Call to UnregisterConverter for a converter that was not registered. Type: " + converter.Name.ToString().Color(Color.Gold));
				}
			}
		}

		internal static bool IsGenericConverterContext(Type rootType)
		{
			return rootType?.BaseType?.Name == typeof(CommandArgumentConverter<>).Name;
		}

		internal static bool IsSpecificConverterContext(Type rootType)
		{
			return rootType?.BaseType?.Name == typeof(CommandArgumentConverter<, >).Name;
		}

		public static void RegisterConverter(Type converter)
		{
			bool flag = IsGenericConverterContext(converter);
			bool flag2 = IsSpecificConverterContext(converter);
			if (!flag && !flag2)
			{
				return;
			}
			Log.Debug($"Trying to process {converter} as specifc={flag2} generic={flag}");
			object item = Activator.CreateInstance(converter);
			MethodInfo method = converter.GetMethod("Parse", BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod);
			if (method == null)
			{
				Log.Error("Can't find TryParse that matches");
				return;
			}
			Type[] genericTypeArguments = converter.BaseType.GenericTypeArguments;
			Type type = genericTypeArguments.FirstOrDefault();
			if (type == null)
			{
				Log.Error("Can't determine generic base type to convert from. ");
				return;
			}
			Type item2 = typeof(ICommandContext);
			if (flag2)
			{
				if (genericTypeArguments.Length != 2 || !typeof(ICommandContext).IsAssignableFrom(genericTypeArguments[1]))
				{
					Log.Error("Can't determine generic base type to convert from.");
					return;
				}
				item2 = genericTypeArguments[1];
			}
			_converters.Add(type, (item, method, item2));
		}

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

		public static void RegisterAll(Assembly assembly)
		{
			Type[] types = assembly.GetTypes();
			Type[] array = types;
			foreach (Type converter in array)
			{
				RegisterConverter(converter);
			}
			Type[] array2 = types;
			foreach (Type type in array2)
			{
				RegisterCommandType(type);
			}
		}

		public static void RegisterCommandType(Type type)
		{
			CommandGroupAttribute customAttribute = type.GetCustomAttribute<CommandGroupAttribute>();
			Assembly assembly = type.Assembly;
			if (customAttribute != null)
			{
			}
			MethodInfo[] methods = type.GetMethods();
			ConstructorInfo customConstructor = (from c in type.GetConstructors()
				where c.GetParameters().Length == 1 && typeof(ICommandContext).IsAssignableFrom(c.GetParameters().SingleOrDefault()?.ParameterType)
				select c).FirstOrDefault();
			MethodInfo[] array = methods;
			foreach (MethodInfo method in array)
			{
				RegisterMethod(assembly, customAttribute, customConstructor, method);
			}
		}

		private static void RegisterMethod(Assembly assembly, CommandGroupAttribute groupAttr, ConstructorInfo customConstructor, MethodInfo method)
		{
			CommandAttribute customAttribute = method.GetCustomAttribute<CommandAttribute>();
			if (customAttribute == null)
			{
				return;
			}
			ParameterInfo[] parameters = method.GetParameters();
			ParameterInfo parameterInfo = parameters.FirstOrDefault();
			if (parameterInfo == null || parameterInfo.ParameterType is ICommandContext)
			{
				Log.Error("Method " + method.Name.ToString().Color(Color.Gold) + " has no CommandContext as first argument");
				return;
			}
			ParameterInfo[] array = parameters.Skip(1).ToArray();
			for (int i = 0; i < array.Length - 1; i++)
			{
				if (array[i].IsDefined(typeof(RemainderAttribute), inherit: false))
				{
					Log.Error($"Method {method.Name.ToString().Color(Color.Gold)} has [Remainder] on parameter {array[i].Name.ToString().Color(Color.Gold)} which is not the last parameter. [Remainder] must be on the last parameter. Command will be ignored.");
					return;
				}
			}
			if (!array.All(delegate(ParameterInfo param)
			{
				if (IsRemainderParameter(param))
				{
					Log.Debug($"Method {method.Name.ToString().Color(Color.Gold)} has a remainder parameter ({param.Name})");
					return true;
				}
				if (_converters.ContainsKey(param.ParameterType))
				{
					Log.Debug($"Method {method.Name.ToString().Color(Color.Gold)} has a parameter of type {param.ParameterType.Name.ToString().Color(Color.Gold)} which is registered as a converter");
					return true;
				}
				TypeConverter converter = TypeDescriptor.GetConverter(param.ParameterType);
				if (converter == null || !converter.CanConvertFrom(typeof(string)))
				{
					Log.Warning($"Parameter {param.Name.ToString().Color(Color.Gold)} could not be converted, so {method.Name.ToString().Color(Color.Gold)} will be ignored.");
					return false;
				}
				return true;
			}))
			{
				return;
			}
			Type constructorType = customConstructor?.GetParameters().Single().ParameterType;
			CommandMetadata commandMetadata = new CommandMetadata(customAttribute, assembly.GetName().Name, method, customConstructor, array, parameterInfo.ParameterType, constructorType, groupAttr);
			string[] array2 = ((groupAttr != null) ? ((groupAttr.ShortHand != null) ? new string[2]
			{
				groupAttr.Name + " ",
				groupAttr.ShortHand + " "
			} : new string[1] { groupAttr.Name + " " }) : new string[1] { "" });
			string[] array3 = ((customAttribute.ShortHand != null) ? new string[2] { customAttribute.Name, customAttribute.ShortHand } : new string[1] { customAttribute.Name });
			string text = ".";
			List<string> list = new List<string>();
			string[] array4 = array2;
			foreach (string text2 in array4)
			{
				string[] array5 = array3;
				foreach (string text3 in array5)
				{
					string text4 = text + text2 + text3;
					_cache.AddCommand(text4, array, commandMetadata);
					list.Add(text4);
				}
			}
			string name = assembly.GetName().Name;
			AssemblyCommandMap.TryGetValue(name, out var value);
			if (value == null)
			{
				value = new Dictionary<CommandMetadata, List<string>>();
			}
			value[commandMetadata] = list;
			AssemblyCommandMap[name] = value;
		}

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

		public static void UnregisterAssembly(Assembly assembly)
		{
			string name = assembly.GetName().Name;
			foreach (TypeInfo definedType in assembly.DefinedTypes)
			{
				_cache.RemoveCommandsFromType(definedType);
				UnregisterConverter(definedType);
			}
			AssemblyCommandMap.Remove(name);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "gg.deca.VampireCommandFramework";

		public const string PLUGIN_NAME = "VampireCommandFramework";

		public const string PLUGIN_VERSION = "0.11.0";
	}
}
namespace VampireCommandFramework.Registry
{
	internal record CacheResult
	{
		internal IEnumerable<(CommandMetadata Command, string[] Args)> Commands { get; }

		internal IEnumerable<CommandMetadata> PartialMatches { get; }

		internal bool IsMatched => Commands != null && Commands.Any();

		internal bool HasPartial => PartialMatches?.Any() ?? false;

		public CacheResult(IEnumerable<(CommandMetadata Command, string[] Args)> commands, IEnumerable<CommandMetadata> partialMatches)
		{
			Commands = commands;
			PartialMatches = partialMatches;
		}

		public CacheResult((CommandMetadata Command, string[] Args)? command, IEnumerable<CommandMetadata> partialMatches)
		{
			Commands = ((!command.HasValue) ? null : new(CommandMetadata, string[])[1] { command.Value });
			PartialMatches = partialMatches;
		}

		[CompilerGenerated]
		protected virtual bool PrintMembers(StringBuilder builder)
		{
			return false;
		}
	}
	internal class CommandCache
	{
		private static Dictionary<Type, HashSet<(string, int)>> _commandAssemblyMap = new Dictionary<Type, HashSet<(string, int)>>();

		internal Dictionary<string, Dictionary<int, List<CommandMetadata>>> _newCache = new Dictionary<string, Dictionary<int, List<CommandMetadata>>>();

		internal Dictionary<string, List<CommandMetadata>> _remainderCache = new Dictionary<string, List<CommandMetadata>>();

		internal void AddCommand(string key, ParameterInfo[] parameters, CommandMetadata command)
		{
			key = key.ToLowerInvariant();
			int num = parameters.Length;
			int num2 = parameters.Where((ParameterInfo p) => p.HasDefaultValue).Count();
			bool flag = parameters.Length != 0 && CommandRegistry.IsRemainderParameter(parameters[^1]);
			if (!_newCache.ContainsKey(key))
			{
				_newCache.Add(key, new Dictionary<int, List<CommandMetadata>>());
			}
			if (flag)
			{
				if (!_remainderCache.ContainsKey(key))
				{
					_remainderCache[key] = new List<CommandMetadata>();
				}
				_remainderCache[key].Add(command);
				Type declaringType = command.Method.DeclaringType;
				HashSet<(string, int)> value;
				HashSet<(string, int)> hashSet = (_commandAssemblyMap.TryGetValue(declaringType, out value) ? value : new HashSet<(string, int)>());
				hashSet.Add((key, -1));
				_commandAssemblyMap[declaringType] = hashSet;
				return;
			}
			for (int i = num - num2; i <= num; i++)
			{
				_newCache[key] = _newCache.GetValueOrDefault(key, new Dictionary<int, List<CommandMetadata>>()) ?? new Dictionary<int, List<CommandMetadata>>();
				if (!_newCache[key].ContainsKey(i))
				{
					_newCache[key][i] = new List<CommandMetadata>();
				}
				_newCache[key][i].Add(command);
				Type declaringType2 = command.Method.DeclaringType;
				HashSet<(string, int)> value2;
				HashSet<(string, int)> hashSet2 = (_commandAssemblyMap.TryGetValue(declaringType2, out value2) ? value2 : new HashSet<(string, int)>());
				hashSet2.Add((key, i));
				_commandAssemblyMap[declaringType2] = hashSet2;
			}
		}

		internal CacheResult GetCommand(string rawInput)
		{
			string text = rawInput.ToLowerInvariant();
			List<CommandMetadata> list = new List<CommandMetadata>();
			List<(CommandMetadata, string[])> list2 = new List<(CommandMetadata, string[])>();
			foreach (var (text3, dictionary2) in _newCache)
			{
				if (!text.StartsWith(text3))
				{
					continue;
				}
				bool flag = text.Length == text3.Length;
				bool flag2 = text.Length > text3.Length && text[text3.Length] == ' ';
				if (!(flag || flag2))
				{
					continue;
				}
				string text4 = (flag ? "" : rawInput.Substring(text3.Length).Trim());
				string[] array = ((text4.Length > 0) ? Utility.GetParts(text4).ToArray() : Array.Empty<string>());
				if (dictionary2.TryGetValue(array.Length, out var value))
				{
					foreach (CommandMetadata item in value)
					{
						list2.Add((item, array));
					}
				}
				if (_remainderCache.TryGetValue(text3, out var value2))
				{
					foreach (CommandMetadata item2 in value2)
					{
						ParameterInfo[] parameters = item2.Method.GetParameters();
						int num = parameters.Count((ParameterInfo p) => !p.HasDefaultValue) - 2;
						if (array.Length >= num)
						{
							list2.Add((item2, array));
						}
					}
				}
				if (list2.Count == 0)
				{
					list.AddRange(dictionary2.Values.SelectMany((List<CommandMetadata> x) => x));
					if (_remainderCache.TryGetValue(text3, out var value3))
					{
						list.AddRange(value3);
					}
				}
			}
			if (list2.Count > 0)
			{
				return new CacheResult(list2, null);
			}
			return new CacheResult(((CommandMetadata Command, string[] Args)?)null, list.Distinct());
		}

		internal CacheResult GetCommandFromAssembly(string rawInput, string assemblyName)
		{
			string text = rawInput.ToLowerInvariant();
			List<CommandMetadata> list = new List<CommandMetadata>();
			List<(CommandMetadata, string[])> list2 = new List<(CommandMetadata, string[])>();
			foreach (var (text3, dictionary2) in _newCache)
			{
				if (!text.StartsWith(text3))
				{
					continue;
				}
				bool flag = text.Length == text3.Length;
				bool flag2 = text.Length > text3.Length && text[text3.Length] == ' ';
				if (!(flag || flag2))
				{
					continue;
				}
				string text4 = (flag ? "" : rawInput.Substring(text3.Length).Trim());
				string[] array = ((text4.Length > 0) ? Utility.GetParts(text4).ToArray() : Array.Empty<string>());
				if (dictionary2.TryGetValue(array.Length, out var value))
				{
					foreach (CommandMetadata item in value.Where((CommandMetadata cmd) => cmd.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)))
					{
						list2.Add((item, array));
					}
				}
				if (_remainderCache.TryGetValue(text3, out var value2))
				{
					foreach (CommandMetadata item2 in value2.Where((CommandMetadata cmd) => cmd.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)))
					{
						ParameterInfo[] parameters = item2.Method.GetParameters();
						int num = parameters.Count((ParameterInfo p) => !p.HasDefaultValue) - 2;
						if (array.Length >= num)
						{
							list2.Add((item2, array));
						}
					}
				}
				if (list2.Count != 0)
				{
					continue;
				}
				list.AddRange(from cmd in dictionary2.Values.SelectMany((List<CommandMetadata> x) => x)
					where cmd.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)
					select cmd);
				if (_remainderCache.TryGetValue(text3, out var value3))
				{
					list.AddRange(value3.Where((CommandMetadata cmd) => cmd.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)));
				}
			}
			if (list2.Count > 0)
			{
				return new CacheResult(list2, null);
			}
			return new CacheResult(((CommandMetadata Command, string[] Args)?)null, list.Distinct());
		}

		internal void RemoveCommandsFromType(Type t)
		{
			if (!_commandAssemblyMap.TryGetValue(t, out var value))
			{
				return;
			}
			foreach (var (key, num) in value)
			{
				Dictionary<int, List<CommandMetadata>> value3;
				List<CommandMetadata> value4;
				if (num == -1)
				{
					if (_remainderCache.TryGetValue(key, out var value2))
					{
						value2.RemoveAll((CommandMetadata cmd) => cmd.Method.DeclaringType == t);
						if (value2.Count == 0)
						{
							_remainderCache.Remove(key);
						}
					}
				}
				else if (_newCache.TryGetValue(key, out value3) && value3.TryGetValue(num, out value4))
				{
					value4.RemoveAll((CommandMetadata cmd) => cmd.Method.DeclaringType == t);
					if (value4.Count == 0)
					{
						value3.Remove(num);
					}
				}
			}
			_commandAssemblyMap.Remove(t);
		}

		internal void Clear()
		{
			_newCache.Clear();
			_remainderCache.Clear();
		}

		internal void Reset()
		{
			throw new NotImplementedException();
		}
	}
	public static class CommandHistory
	{
		private static Dictionary<string, List<(string input, CommandMetadata Command, object[] Args)>> _commandHistory = new Dictionary<string, List<(string, CommandMetadata, object[])>>();

		private const int MAX_COMMAND_HISTORY = 10;

		private static HashSet<string> _loadedHistories = new HashSet<string>();

		private static readonly Queue<(string filePath, string[] inputs)> _saveQueue = new Queue<(string, string[])>();

		private static volatile bool _saveThreadRunning = false;

		private static string HistoryDirectory => Path.Combine(Path.Combine(Paths.ConfigPath, "VampireCommandFramework"), "CommandHistory");

		internal static void Reset()
		{
			WaitOnSaves();
			_commandHistory.Clear();
			_loadedHistories.Clear();
		}

		internal static void WaitOnSaves()
		{
			while (_saveThreadRunning)
			{
				Thread.Sleep(1);
			}
		}

		internal static bool IsHistoryLoaded(string contextName)
		{
			return _loadedHistories.Contains(contextName);
		}

		internal static void EnsureHistoryLoaded(ICommandContext ctx)
		{
			string name = ctx.Name;
			if (!_loadedHistories.Contains(name))
			{
				LoadHistoryFromFile(ctx, name);
			}
		}

		internal static void AddToHistory(ICommandContext ctx, string input, CommandMetadata command, object[] args)
		{
			string name = ctx.Name;
			if (!_commandHistory.TryGetValue(name, out List<(string, CommandMetadata, object[])> value))
			{
				value = new List<(string, CommandMetadata, object[])>();
				_commandHistory[name] = value;
			}
			for (int i = 0; i < value.Count; i++)
			{
				(string, CommandMetadata, object[]) tuple = value[i];
				if (!(tuple.Item2 == null) && tuple.Item2.Method == command.Method && tuple.Item2.Attribute.Name == command.Attribute.Name && ArgsEqual(tuple.Item3, args))
				{
					value.RemoveAt(i);
					break;
				}
			}
			value.Insert(0, (input, command, args));
			if (value.Count > 10)
			{
				value.RemoveAt(value.Count - 1);
			}
			SaveHistoryToFile(name, value);
		}

		internal static CommandResult HandleHistoryCommand(ICommandContext ctx, string input, Func<ICommandContext, string, CommandResult> handleCommand, Func<ICommandContext, CommandMetadata, object[], CommandResult> executeCommandWithArgs)
		{
			string name = ctx.Name;
			string text = input.Substring(2).Trim();
			if (!_commandHistory.TryGetValue(name, out List<(string, CommandMetadata, object[])> value) || value.Count == 0)
			{
				ctx.SysReply("[error]".Color(Color.Red) + " No command history available.");
				return CommandResult.CommandError;
			}
			if (text == "list" || text == "l")
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Command history:");
				for (int i = 0; i < value.Count; i++)
				{
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder2);
					handler.AppendFormatted((i + 1).ToString().Color(Color.Gold));
					handler.AppendLiteral(". ");
					handler.AppendFormatted(value[i].Item1.Color(Color.Command));
					stringBuilder2.AppendLine(ref handler);
				}
				ctx.SysPaginatedReply(stringBuilder);
				return CommandResult.Success;
			}
			if (int.TryParse(text, out var result) && result > 0 && result <= value.Count)
			{
				(string, CommandMetadata, object[]) tuple = value[result - 1];
				ctx.SysReply("Executing command " + result.ToString().Color(Color.Gold) + ": " + tuple.Item1.Color(Color.Command));
				if (tuple.Item2 != null && tuple.Item3 != null)
				{
					object[] array = tuple.Item3.ToArray();
					array[0] = ctx;
					return executeCommandWithArgs(ctx, tuple.Item2, array);
				}
				return handleCommand(ctx, tuple.Item1);
			}
			if (string.IsNullOrWhiteSpace(text))
			{
				(string, CommandMetadata, object[]) tuple2 = value[0];
				ctx.SysReply("Repeating most recent command: " + tuple2.Item1.Color(Color.Command));
				if (tuple2.Item2 != null && tuple2.Item3 != null)
				{
					object[] array2 = tuple2.Item3.ToArray();
					array2[0] = ctx;
					return executeCommandWithArgs(ctx, tuple2.Item2, array2);
				}
				return handleCommand(ctx, tuple2.Item1);
			}
			ctx.SysReply($"{"[error]".Color(Color.Red)} Invalid command history selection. Use {".! list".Color(Color.Command)} to see available commands or {".! #".Color(Color.Command)} to execute a specific command.");
			return CommandResult.UsageError;
		}

		private static bool ArgsEqual(object[] args1, object[] args2)
		{
			if (args1 == null && args2 == null)
			{
				return true;
			}
			if (args1 == null || args2 == null)
			{
				return false;
			}
			if (args1.Length != args2.Length)
			{
				return false;
			}
			for (int i = 1; i < args1.Length; i++)
			{
				if (!object.Equals(args1[i], args2[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static void SaveHistoryToFile(string contextName, List<(string input, CommandMetadata Command, object[] Args)> history)
		{
			try
			{
				string text = string.Join("_", contextName.Split(Path.GetInvalidFileNameChars()));
				string item = Path.Combine(HistoryDirectory, text + ".txt");
				string[] item2 = history.Select(((string input, CommandMetadata Command, object[] Args) h) => h.input).ToArray();
				lock (_saveQueue)
				{
					_saveQueue.Enqueue((item, item2));
					if (!_saveThreadRunning)
					{
						_saveThreadRunning = true;
						Thread thread = new Thread(ProcessSaveQueue);
						thread.IsBackground = true;
						thread.Name = "VCF-HistorySave";
						thread.Start();
					}
				}
			}
			catch (Exception ex)
			{
				Log.Error("Failed to save command history for context " + contextName + ": " + ex.Message);
			}
		}

		private static bool TryDequeueFromSaveQueue(out (string filePath, string[] inputs) item)
		{
			lock (_saveQueue)
			{
				if (_saveQueue.TryDequeue(out item))
				{
					return true;
				}
				_saveThreadRunning = false;
				return false;
			}
		}

		private static void ProcessSaveQueue()
		{
			(string, string[]) item;
			while (TryDequeueFromSaveQueue(out item))
			{
				try
				{
					if (!Directory.Exists(HistoryDirectory))
					{
						Directory.CreateDirectory(HistoryDirectory);
					}
					File.WriteAllLines(item.Item1, item.Item2);
				}
				catch (Exception ex)
				{
					Log.Error("Failed to save command history to " + item.Item1 + ": " + ex.Message);
				}
			}
		}

		private static void LoadHistoryFromFile(ICommandContext ctx, string contextName)
		{
			try
			{
				string text = string.Join("_", contextName.Split(Path.GetInvalidFileNameChars()));
				string path = Path.Combine(HistoryDirectory, text + ".txt");
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllLines(path);
				if (array.Length == 0)
				{
					return;
				}
				List<(string, CommandMetadata, object[])> list = new List<(string, CommandMetadata, object[])>();
				string[] array2 = array;
				foreach (string text2 in array2)
				{
					try
					{
						var (commandMetadata, array3) = ParseCommandForHistory(ctx, text2);
						if (commandMetadata != null && array3 != null)
						{
							list.Add((text2, commandMetadata, array3));
						}
						else
						{
							list.Add((text2, null, null));
						}
					}
					catch (Exception)
					{
						list.Add((text2, null, null));
					}
				}
				_commandHistory[contextName] = list;
			}
			catch (Exception ex2)
			{
				Log.Error("Failed to load command history for context " + contextName + ": " + ex2.Message);
			}
			finally
			{
				_loadedHistories.Add(contextName);
			}
		}

		private static (CommandMetadata command, object[] args) ParseCommandForHistory(ICommandContext ctx, string input)
		{
			try
			{
				if (!input.StartsWith("."))
				{
					return (null, null);
				}
				ParsedCommandInput parsedCommandInput = CommandRegistry.ParseInput(input);
				CacheResult commandFromCache = CommandRegistry.GetCommandFromCache(parsedCommandInput.CommandInput, parsedCommandInput.AssemblyName);
				if (commandFromCache == null || !commandFromCache.IsMatched)
				{
					commandFromCache = CommandRegistry.GetCommandFromCache(input);
				}
				IEnumerable<(CommandMetadata, string[])> commands = commandFromCache.Commands;
				if (!commandFromCache.IsMatched || !commands.Any())
				{
					return (null, null);
				}
				foreach (var (commandMetadata, args) in commands)
				{
					if (CommandRegistry.CanCommandExecute(ctx, commandMetadata))
					{
						var (flag, item, text) = CommandRegistry.TryConvertParameters(ctx, commandMetadata, args, parsedCommandInput.CommandInput);
						if (flag)
						{
							return (commandMetadata, item);
						}
					}
				}
				return (null, null);
			}
			catch (Exception)
			{
				return (null, null);
			}
		}
	}
	internal record CommandMetadata(CommandAttribute Attribute, string AssemblyName, MethodInfo Method, ConstructorInfo Constructor, ParameterInfo[] Parameters, Type ContextType, Type ConstructorType, CommandGroupAttribute GroupAttribute);
	internal readonly struct ParsedCommandInput
	{
		internal string AssemblyName { get; }

		internal string CommandInput { get; }

		internal string AfterPrefixAndAssembly { get; }

		internal bool HasAssembly => AssemblyName != null;

		internal ParsedCommandInput(string assemblyName, string commandInput, string afterPrefixAndAssembly)
		{
			AssemblyName = assemblyName;
			CommandInput = commandInput;
			AfterPrefixAndAssembly = afterPrefixAndAssembly;
		}
	}
}
namespace VampireCommandFramework.Framework
{
	internal static class ChatDrainPatch
	{
		[HarmonyPatch(typeof(ServerBootstrapSystem), "OnUpdate")]
		public static class DrainTick_Patch
		{
			[HarmonyPostfix]
			public static void Postfix()
			{
				try
				{
					ChatMessageQueue.DrainOneTick();
				}
				catch (Exception value)
				{
					Log.Error($"ChatMessageQueue.DrainOneTick failed: {value}");
				}
			}
		}

		public static void Install()
		{
			ChatMessageQueue.SendSink = delegate(object userObj, string message)
			{
				//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_0009: 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_0014: 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)
				User val = (User)userObj;
				FixedString512Bytes val2 = FixedString512Bytes.op_Implicit(message);
				ServerChatUtils.SendSystemMessageToClient(VWorld.Server.EntityManager, val, ref val2);
			};
		}
	}
	internal static class ChatMessageQueue
	{
		internal static readonly Dictionary<ulong, (object User, Queue<string> Queue)> _queues = new Dictionary<ulong, (object, Queue<string>)>();

		internal static readonly HashSet<ulong> _sentThisTick = new HashSet<ulong>();

		internal static Action<object, string> SendSink = delegate
		{
		};

		internal static void Send(User user, string message)
		{
			//IL_0001: 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)
			Send(user.PlatformId, user, message);
		}

		internal static void Send(ulong platformId, string message)
		{
			Send(platformId, null, message);
		}

		private static void Send(ulong platformId, object user, string message)
		{
			if (!_sentThisTick.Contains(platformId) && (!_queues.TryGetValue(platformId, out (object, Queue<string>) value) || value.Item2.Count == 0))
			{
				SendSink(user, message);
				_sentThisTick.Add(platformId);
			}
			else
			{
				(object, Queue<string>) value2 = (_queues.TryGetValue(platformId, out value2) ? (user, value2.Item2) : (user, new Queue<string>()));
				value2.Item2.Enqueue(message);
				_queues[platformId] = value2;
			}
		}

		internal static void DrainOneTick()
		{
			_sentThisTick.Clear();
			if (_queues.Count == 0)
			{
				return;
			}
			List<ulong> list = new List<ulong>(_queues.Keys);
			foreach (ulong item in list)
			{
				if (!_queues.TryGetValue(item, out (object, Queue<string>) value) || value.Item2.Count == 0)
				{
					_queues.Remove(item);
					continue;
				}
				string arg = value.Item2.Dequeue();
				SendSink(value.Item1, arg);
				_sentThisTick.Add(item);
				if (value.Item2.Count == 0)
				{
					_queues.Remove(item);
				}
			}
		}

		internal static void Clear(ulong platformId)
		{
			_queues.Remove(platformId);
			_sentThisTick.Remove(platformId);
		}

		internal static void ResetForTests()
		{
			_queues.Clear();
			_sentThisTick.Clear();
			SendSink = delegate
			{
			};
		}
	}
}
namespace VampireCommandFramework.Common
{
	internal static class Log
	{
		internal static ManualLogSource Instance { get; set; }

		public static void Warning(string s)
		{
			LogOrConsole(s, delegate(string s)
			{
				Instance.LogWarning((object)s);
			});
		}

		public static void Error(string s)
		{
			LogOrConsole(s, delegate(string s)
			{
				Instance.LogError((object)s);
			});
		}

		public static void Debug(string s)
		{
			LogOrConsole(s, delegate(string s)
			{
				Instance.LogDebug((object)s);
			});
		}

		public static void Info(string s)
		{
			LogOrConsole(s, delegate(string s)
			{
				Instance.LogInfo((object)s);
			});
		}

		private static void LogOrConsole(string message, Action<string> instanceLog)
		{
			if (Instance == null)
			{
				Console.WriteLine(message);
			}
			else
			{
				instanceLog(message);
			}
		}
	}
	internal static class Utility
	{
		private const int MAX_MESSAGE_SIZE = 460;

		internal static List<string> GetParts(string input)
		{
			List<string> list = new List<string>();
			if (string.IsNullOrWhiteSpace(input))
			{
				return list;
			}
			bool flag = false;
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < input.Length; i++)
			{
				char c = input[i];
				if (c == '\\' && i + 1 < input.Length)
				{
					char c2 = input[i + 1];
					if (c2 == '"')
					{
						stringBuilder.Append(c2);
						i++;
						continue;
					}
				}
				switch (c)
				{
				case '"':
					flag = !flag;
					continue;
				case ' ':
					if (!flag)
					{
						if (stringBuilder.Length > 0)
						{
							list.Add(stringBuilder.ToString());
							stringBuilder.Clear();
						}
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			return list;
		}

		internal static void InternalError(this ICommandContext ctx)
		{
			ctx.SysReply("An internal error has occurred.");
		}

		internal static void SysReply(this ICommandContext ctx, string input)
		{
			ctx.Reply("[vcf] ".Color(Color.Primary) + input.Color(Color.Beige));
		}

		internal static void SysPaginatedReply(this ICommandContext ctx, StringBuilder input)
		{
			ctx.SysPaginatedReply(input.ToString());
		}

		internal static void SysPaginatedReply(this ICommandContext ctx, string input)
		{
			if (input.Length <= 460)
			{
				ctx.SysReply(input);
				return;
			}
			string[] array = SplitIntoPages(input);
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.TrimEnd('\n', '\r', ' ');
				text2 = Environment.NewLine + text2;
				ctx.SysReply(text2);
			}
		}

		internal static string[] SplitIntoPages(string rawText, int pageSize = 460)
		{
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = rawText.Split("\n");
			List<string> list2 = new List<string>();
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (text.Length > pageSize)
				{
					string text2 = text;
					while (!string.IsNullOrWhiteSpace(text2) && text2.Length > pageSize)
					{
						int num = text2.LastIndexOf(' ', pageSize - (int)((double)pageSize * 0.05));
						if (num <= 0)
						{
							num = Math.Min(pageSize - 1, text2.Length);
						}
						list2.Add(text2.Substring(0, num));
						text2 = text2.Substring(num);
					}
					list2.Add(text2);
				}
				else
				{
					list2.Add(text);
				}
			}
			foreach (string item in list2)
			{
				if (stringBuilder.Length + item.Length > pageSize)
				{
					list.Add(stringBuilder.ToString());
					stringBuilder.Clear();
				}
				stringBuilder.AppendLine(item);
			}
			if (stringBuilder.Length > 0)
			{
				list.Add(stringBuilder.ToString());
			}
			return list.ToArray();
		}
	}
	internal static class VersionChecker
	{
		private class InstalledPluginInfo
		{
			public string GUID { get; set; }

			public string Name { get; set; }

			public string Version { get; set; }
		}

		public static void ListAllPluginVersions(Entity userEntity = default(Entity))
		{
			//IL_0027: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<InstalledPluginInfo> installedPlugins = GetInstalledPlugins();
				if (installedPlugins.Count == 0)
				{
					LogInfoAndSendMessageToClient(userEntity, "No plugins found.");
					return;
				}
				LogInfoAndSendMessageToClient(userEntity, $"Installed Plugins ({installedPlugins.Count}):");
				foreach (InstalledPluginInfo item in installedPlugins.OrderBy((InstalledPluginInfo p) => p.Name))
				{
					string text = item.Name.Color(Color.Command) + ": " + item.Version.Color(Color.Green);
					string message = "[vcf] ".Color(Color.Primary) + text;
					SendMessageToClient(userEntity, message);
				}
			}
			catch (Exception ex)
			{
				Log.Error("Error listing plugin versions: " + ex.Message);
			}
		}

		private static void SendMessageToClient(Entity userEntity, string message)
		{
			//IL_0001: 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_000a: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0089: 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_008f: 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)
			if (userEntity == default(Entity))
			{
				return;
			}
			try
			{
				World server = VWorld.Server;
				if (server == null)
				{
					return;
				}
				_ = server.EntityManager;
				if (false)
				{
					return;
				}
				EntityManager entityManager = VWorld.Server.EntityManager;
				if (!((EntityManager)(ref entityManager)).Exists(userEntity))
				{
					return;
				}
				entityManager = VWorld.Server.EntityManager;
				if (((EntityManager)(ref entityManager)).HasComponent<User>(userEntity))
				{
					entityManager = VWorld.Server.EntityManager;
					User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(userEntity);
					if (componentData.IsConnected)
					{
						FixedString512Bytes val = default(FixedString512Bytes);
						((FixedString512Bytes)(ref val))..ctor(message);
						ServerChatUtils.SendSystemMessageToClient(VWorld.Server.EntityManager, componentData, ref val);
					}
				}
			}
			catch (Exception ex)
			{
				Log.Debug("Could not send message to client (user may have disconnected): " + ex.Message);
			}
		}

		private static void LogInfoAndSendMessageToClient(Entity userEntity, string message)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Log.Info(message);
			SendMessageToClient(userEntity, message);
		}

		private static List<InstalledPluginInfo> GetInstalledPlugins()
		{
			List<InstalledPluginInfo> list = new List<InstalledPluginInfo>();
			foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins)
			{
				PluginInfo value = plugin.Value;
				if (((value != null) ? value.Metadata : null) != null)
				{
					list.Add(new InstalledPluginInfo
					{
						GUID = value.Metadata.GUID,
						Name = value.Metadata.Name,
						Version = ((object)value.Metadata.Version).ToString()
					});
				}
			}
			return list;
		}
	}
}
namespace VampireCommandFramework.Breadstone
{
	[HarmonyPriority(200)]
	[HarmonyBefore(new string[] { "gg.deca.Bloodstone" })]
	[HarmonyPatch(typeof(ChatMessageSystem), "OnUpdate")]
	public static class ChatMessageSystem_Patch
	{
		public static void Prefix(ChatMessageSystem __instance)
		{
			//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_000b: 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_0015: 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_001e: 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_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_0037: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			//IL_0055: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00b5: 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_0142: 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_014d: 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_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			EntityQuery _query_661171423_ = __instance.__query_661171423_0;
			Enumerator<Entity> enumerator = ((EntityQuery)(ref _query_661171423_)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2)).GetEnumerator();
			while (enumerator.MoveNext())
			{
				Entity current = enumerator.Current;
				EntityManager entityManager = ((ComponentSystemBase)__instance).EntityManager;
				FromCharacter componentData = ((EntityManager)(ref entityManager)).GetComponentData<FromCharacter>(current);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				User componentData2 = ((EntityManager)(ref entityManager)).GetComponentData<User>(componentData.User);
				entityManager = ((ComponentSystemBase)__instance).EntityManager;
				ChatMessageEvent componentData3 = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageEvent>(current);
				string text = ((object)(FixedString512Bytes)(ref componentData3.MessageText)).ToString();
				if (!text.StartsWith(".") || text.StartsWith(".."))
				{
					continue;
				}
				VChatEvent e = new VChatEvent(componentData.User, componentData.Character, text, componentData3.MessageType, componentData2);
				ChatCommandContext ctx = new ChatCommandContext(e);
				CommandResult commandResult;
				try
				{
					commandResult = CommandRegistry.Handle(ctx, text);
				}
				catch (Exception value)
				{
					Log.Error($"Error while handling chat message {value}");
					continue;
				}
				if (commandResult == CommandResult.Success && text.StartsWith(".help-legacy", StringComparison.InvariantCulture))
				{
					componentData3.MessageText = FixedString512Bytes.op_Implicit(text.Replace("-legacy", string.Empty));
					entityManager = ((ComponentSystemBase)__instance).EntityManager;
					((EntityManager)(ref entityManager)).SetComponentData<ChatMessageEvent>(current, componentData3);
					continue;
				}
				if (commandResult == CommandResult.Unmatched)
				{
					StringBuilder stringBuilder = new StringBuilder();
					StringBuilder stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder3 = stringBuilder2;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(19, 1, stringBuilder2);
					handler.AppendLiteral("Command not found: ");
					handler.AppendFormatted(text.Color(Color.Command));
					stringBuilder3.AppendLine(ref handler);
					string[] array = CommandRegistry.FindCloseMatches(ctx, text).ToArray();
					if (array.Length != 0)
					{
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder4 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(14, 1, stringBuilder2);
						handler.AppendLiteral("Did you mean: ");
						handler.AppendFormatted(string.Join(", ", array.Select((string c) => c.Color(Color.Command))));
						stringBuilder4.AppendLine(ref handler);
					}
					ctx.SysReply(stringBuilder.ToString());
				}
				entityManager = VWorld.Server.EntityManager;
				((EntityManager)(ref entityManager)).DestroyEntity(current);
			}
		}
	}
	public class VChatEvent
	{
		public Entity SenderUserEntity { get; }

		public Entity SenderCharacterEntity { get; }

		public string Message { get; }

		public ChatMessageType Type { get; }

		public bool Cancelled { get; private set; } = false;


		public User User { get; }

		internal VChatEvent(Entity userEntity, Entity characterEntity, string message, ChatMessageType type, User user)
		{
			//IL_0010: 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_0017: 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_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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			SenderUserEntity = userEntity;
			SenderCharacterEntity = characterEntity;
			Message = message;
			Type = type;
			User = user;
		}

		public void Cancel()
		{
			Cancelled = true;
		}
	}
	internal static class VWorld
	{
		private static World _serverWorld;

		public static World Server
		{
			get
			{
				if (_serverWorld != null)
				{
					return _serverWorld;
				}
				_serverWorld = GetWorld("Server") ?? throw new Exception("There is no Server world (yet). Did you install a server mod on the client?");
				return _serverWorld;
			}
		}

		public static bool IsServer => Application.productName == "VRisingServer";

		public static void SendSystemMessage(this User user, string message)
		{
			//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_000d: 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)
			FixedString512Bytes val = FixedString512Bytes.op_Implicit(message);
			ServerChatUtils.SendSystemMessageToClient(Server.EntityManager, user, ref val);
		}

		private static World GetWorld(string name)
		{
			Enumerator<World> enumerator = World.s_AllWorlds.GetEnumerator();
			while (enumerator.MoveNext())
			{
				World current = enumerator.Current;
				if (current.Name == name)
				{
					_serverWorld = current;
					return current;
				}
			}
			return null;
		}
	}
}
namespace VampireCommandFramework.Basics
{
	[CommandGroup("config", null)]
	public class BepInExConfigCommands
	{
		[Command("dump", null, null, null, null, true)]
		public void DumpConfig(ICommandContext ctx, string pluginGuid)
		{
			var (guid, val2) = (KeyValuePair<string, PluginInfo>)(ref ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.FirstOrDefault((KeyValuePair<string, PluginInfo> x) => x.Value.Metadata.GUID.Contains(pluginGuid, StringComparison.InvariantCultureIgnoreCase)));
			if (val2 != null)
			{
				object instance = val2.Instance;
				BasePlugin val3 = (BasePlugin)((instance is BasePlugin) ? instance : null);
				if (val3 != null)
				{
					DumpConfig(ctx, guid, val3);
					return;
				}
			}
			foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins)
			{
				ctx.SysReply("Found: " + plugin.Value.Metadata.GUID);
			}
			throw ctx.Error("Can not find that plugin");
		}

		[Command("set", null, null, null, null, true)]
		public void DumpConfig(ICommandContext ctx, string pluginGuid, string section, string key, string value)
		{
			var (text2, val2) = (KeyValuePair<string, PluginInfo>)(ref ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.FirstOrDefault((KeyValuePair<string, PluginInfo> x) => x.Value.Metadata.GUID.Contains(pluginGuid, StringComparison.InvariantCultureIgnoreCase)));
			if (val2 != null)
			{
				object instance = val2.Instance;
				BasePlugin val3 = (BasePlugin)((instance is BasePlugin) ? instance : null);
				if (val3 != null)
				{
					var (val6, val7) = (KeyValuePair<ConfigDefinition, ConfigEntryBase>)(ref ((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)val3.Config).FirstOrDefault((KeyValuePair<ConfigDefinition, ConfigEntryBase> k) => k.Key.Section.Equals(section, StringComparison.InvariantCultureIgnoreCase) && k.Key.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)));
					if (val6 == (ConfigDefinition)null)
					{
						throw ctx.Error("Could not find property");
					}
					try
					{
						object value2 = TomlTypeConverter.ConvertToValue(value, val7.SettingType);
						val7.SetSerializedValue(value);
						if (!val3.Config.SaveOnConfigSet)
						{
							val3.Config.Save();
						}
						ctx.SysReply($"Set {val6.Key} = {value2}");
						return;
					}
					catch (Exception)
					{
						throw ctx.Error($"Can not convert {value} to {val7.SettingType}");
					}
				}
			}
			foreach (KeyValuePair<string, PluginInfo> plugin in ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins)
			{
				ctx.SysReply("Found: " + plugin.Value.Metadata.GUID);
			}
			throw ctx.Error("Can not find that plugin");
		}

		private static void DumpConfig(ICommandContext ctx, string guid, BasePlugin plugin)
		{
			ConfigFile config = plugin.Config;
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Path: " + config.ConfigFilePath);
			StringBuilder stringBuilder2 = stringBuilder;
			StringBuilder stringBuilder3 = stringBuilder2;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(33, 2, stringBuilder2);
			handler.AppendLiteral("Dumping config for ");
			handler.AppendFormatted(guid.Color("#f0f"));
			handler.AppendLiteral(" with ");
			handler.AppendFormatted(((IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config).Count());
			handler.AppendLiteral(" entries");
			stringBuilder3.AppendLine(ref handler);
			foreach (IGrouping<string, KeyValuePair<ConfigDefinition, ConfigEntryBase>> item in from k in (IEnumerable<KeyValuePair<ConfigDefinition, ConfigEntryBase>>)config
				group k by k.Key.Section into k
				orderby k.Key
				select k)
			{
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(2, 1, stringBuilder2);
				handler.AppendLiteral("[");
				handler.AppendFormatted(item.Key);
				handler.AppendLiteral("]");
				stringBuilder4.AppendLine(ref handler);
				foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item2 in item)
				{
					item2.Deconstruct(out var key, out var value);
					ConfigDefinition val = key;
					ConfigEntryBase val2 = value;
					stringBuilder2 = stringBuilder;
					StringBuilder stringBuilder5 = stringBuilder2;
					handler = new StringBuilder.AppendInterpolatedStringHandler(3, 2, stringBuilder2);
					handler.AppendFormatted(val.Key.Color(Color.Beige));
					handler.AppendLiteral(" = ");
					handler.AppendFormatted(val2.BoxedValue.ToString().Color(Color.LightGrey));
					stringBuilder5.AppendLine(ref handler);
				}
			}
			ctx.SysPaginatedReply(stringBuilder);
		}
	}
	internal static class HelpCommands
	{
		private static readonly Regex _trailingLongDashRegex = new Regex("-\\d+$");

		[Command("help-legacy", null, null, "Passes through a .help command that is compatible with other mods that don't use VCF.", null, false)]
		public static void HelpLegacy(ICommandContext ctx, string search = null)
		{
			ctx.SysReply("Attempting compatible .help " + search + " for non-VCF mods.");
		}

		[Command("help", null, null, null, null, false)]
		public static void HelpCommand(ICommandContext ctx, string search = null, string filter = null)
		{
			if (!string.IsNullOrEmpty(search))
			{
				KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> assembly = CommandRegistry.AssemblyCommandMap.FirstOrDefault((KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> x) => x.Key.StartsWith(search, StringComparison.OrdinalIgnoreCase));
				if (assembly.Value != null)
				{
					StringBuilder stringBuilder = new StringBuilder();
					PrintAssemblyHelp(ctx, assembly, stringBuilder, filter);
					ctx.SysPaginatedReply(stringBuilder);
					return;
				}
				IEnumerable<KeyValuePair<CommandMetadata, List<string>>> source = CommandRegistry.AssemblyCommandMap.SelectMany((KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> x) => x.Value);
				IEnumerable<KeyValuePair<CommandMetadata, List<string>>> source2 = source.Where((KeyValuePair<CommandMetadata, List<string>> x) => string.Equals(x.Key.Attribute.Id, search, StringComparison.InvariantCultureIgnoreCase) || string.Equals(x.Key.Attribute.Name, search, StringComparison.InvariantCultureIgnoreCase) || (x.Key.GroupAttribute != null && string.Equals(x.Key.GroupAttribute.Name, search, StringComparison.InvariantCultureIgnoreCase)) || x.Value.Contains<string>(search, StringComparer.InvariantCultureIgnoreCase));
				source2 = from kvp in source2
					where CommandRegistry.CanCommandExecute(ctx, kvp.Key)
					where filter == null || kvp.Key.Attribute.Name.Contains(filter, StringComparison.InvariantCultureIgnoreCase)
					select kvp;
				if (!source2.Any())
				{
					throw ctx.Error("Could not find any commands for \"" + search.Color(Color.Gold) + "\"");
				}
				StringBuilder stringBuilder2 = new StringBuilder();
				foreach (KeyValuePair<CommandMetadata, List<string>> item2 in source2)
				{
					GenerateFullHelp(item2.Key, item2.Value, stringBuilder2);
				}
				ctx.SysPaginatedReply(stringBuilder2);
				return;
			}
			StringBuilder stringBuilder3 = new StringBuilder();
			StringBuilder stringBuilder4 = stringBuilder3;
			StringBuilder stringBuilder5 = stringBuilder4;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(16, 1, stringBuilder4);
			handler.AppendLiteral("Listing ");
			handler.AppendFormatted(Format.B("all"));
			handler.AppendLiteral(" plugins");
			stringBuilder5.AppendLine(ref handler);
			stringBuilder4 = stringBuilder3;
			StringBuilder stringBuilder6 = stringBuilder4;
			handler = new StringBuilder.AppendInterpolatedStringHandler(32, 1, stringBuilder4);
			handler.AppendLiteral("Use ");
			handler.AppendFormatted(Format.B(".help <plugin>").Color(Color.Gold));
			handler.AppendLiteral(" for commands in that plugin");
			stringBuilder6.AppendLine(ref handler);
			foreach (string item3 in from x in CommandRegistry.AssemblyCommandMap
				where x.Value.Keys.Any((CommandMetadata c) => CommandRegistry.CanCommandExecute(ctx, c))
				select x.Key into x
				orderby x
				select x)
			{
				stringBuilder4 = stringBuilder3;
				StringBuilder stringBuilder7 = stringBuilder4;
				handler = new StringBuilder.AppendInterpolatedStringHandler(0, 1, stringBuilder4);
				handler.AppendFormatted(item3.Color(Color.Lilac));
				stringBuilder7.AppendLine(ref handler);
			}
			ctx.SysPaginatedReply(stringBuilder3);
			static void GenerateFullHelp(CommandMetadata command, List<string> aliases, StringBuilder sb)
			{
				StringBuilder stringBuilder8 = sb;
				StringBuilder stringBuilder9 = stringBuilder8;
				StringBuilder.AppendInterpolatedStringHandler handler2 = new StringBuilder.AppendInterpolatedStringHandler(1, 2, stringBuilder8);
				handler2.AppendFormatted(Format.B(command.Attribute.Name).Color(Color.LightRed));
				handler2.AppendLiteral(" ");
				handler2.AppendFormatted(command.Attribute.Description.Color(Color.SoftBGrey));
				stringBuilder9.AppendLine(ref handler2);
				sb.AppendLine(GetShortHelp(command));
				stringBuilder8 = sb;
				StringBuilder stringBuilder10 = stringBuilder8;
				handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder8);
				handler2.AppendFormatted(Format.B("Aliases").Underline().Color(Color.Pink));
				handler2.AppendLiteral(": ");
				handler2.AppendFormatted(string.Join(", ", aliases).Italic());
				stringBuilder10.AppendLine(ref handler2);
				IEnumerable<Type> enumerable = from t in command.Parameters.Select((ParameterInfo p) => p.ParameterType).Distinct()
					where t.IsEnum
					select t;
				foreach (Type item4 in enumerable)
				{
					stringBuilder8 = sb;
					StringBuilder stringBuilder11 = stringBuilder8;
					handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder8);
					handler2.AppendFormatted((item4.Name + " Values").Bold().Underline().Color(Color.Pink));
					handler2.AppendLiteral(": ");
					handler2.AppendFormatted(string.Join(", ", Enum.GetNames(item4)).Color(Color.Command));
					stringBuilder11.AppendLine(ref handler2);
				}
				IEnumerable<Type> enumerable2 = from p in command.Parameters.Select((ParameterInfo p) => p.ParameterType).Distinct()
					where CommandRegistry._converters.ContainsKey(p)
					select p;
				foreach (Type item5 in enumerable2)
				{
					object item = CommandRegistry._converters[item5].instance;
					if (item is IConverterUsage)
					{
						IConverterUsage converterUsage = item as IConverterUsage;
						stringBuilder8 = sb;
						StringBuilder stringBuilder12 = stringBuilder8;
						handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder8);
						handler2.AppendFormatted((item5.Name ?? "").Bold());
						handler2.AppendLiteral(": ");
						handler2.AppendFormatted(converterUsage.Usage);
						stringBuilder12.AppendLine(ref handler2);
					}
				}
			}
		}

		[Command("help-all", null, null, "Returns all plugin commands", null, false)]
		public static void HelpAllCommand(ICommandContext ctx, string filter = null)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (filter == null)
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder2);
				handler.AppendLiteral("Listing ");
				handler.AppendFormatted(Format.B("all"));
				handler.AppendLiteral(" commands");
				stringBuilder3.AppendLine(ref handler);
			}
			else
			{
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(36, 2, stringBuilder2);
				handler.AppendLiteral("Listing ");
				handler.AppendFormatted(Format.B("all"));
				handler.AppendLiteral(" commands matching filter '");
				handler.AppendFormatted(filter);
				handler.AppendLiteral("'");
				stringBuilder4.AppendLine(ref handler);
			}
			bool flag = false;
			foreach (KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> item in CommandRegistry.AssemblyCommandMap.Where((KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> x) => x.Value.Keys.Any((CommandMetadata c) => CommandRegistry.CanCommandExecute(ctx, c) && (filter == null || GetShortHelp(c).Contains(filter, StringComparison.InvariantCultureIgnoreCase)))))
			{
				PrintAssemblyHelp(ctx, item, stringBuilder, filter);
				flag = true;
			}
			if (!flag)
			{
				throw ctx.Error("Could not find any commands for \"" + filter + "\"");
			}
			ctx.SysPaginatedReply(stringBuilder);
		}

		private static void PrintAssemblyHelp(ICommandContext ctx, KeyValuePair<string, Dictionary<CommandMetadata, List<string>>> assembly, StringBuilder sb, string filter = null)
		{
			string key = assembly.Key;
			key = _trailingLongDashRegex.Replace(key, "");
			sb.AppendLine(("Commands from " + key.Medium().Color(Color.Primary) + ":").Underline());
			IEnumerable<CommandMetadata> source = assembly.Value.Keys.Where((CommandMetadata c) => CommandRegistry.CanCommandExecute(ctx, c));
			foreach (CommandMetadata item in source.OrderBy((CommandMetadata c) => ((c.GroupAttribute != null) ? (c.GroupAttribute.Name + " ") : "") + c.Attribute.Name))
			{
				string shortHelp = GetShortHelp(item);
				if (filter == null || shortHelp.Contains(filter, StringComparison.InvariantCultureIgnoreCase))
				{
					sb.AppendLine(shortHelp);
				}
			}
		}

		internal static string GetShortHelp(CommandMetadata command)
		{
			CommandAttribute attribute = command.Attribute;
			string text = (string.IsNullOrEmpty(command.GroupAttribute?.Name) ? string.Empty : (command.GroupAttribute.Name + " "));
			string input = text + attribute.Name;
			string orGenerateUsage = GetOrGenerateUsage(command);
			string text2 = ".".Color(Color.Yellow);
			string text3 = input.Color(Color.Beige);
			return text2 + text3 + orGenerateUsage;
		}

		internal static string GetOrGenerateUsage(CommandMetadata command)
		{
			string text = command.Attribute.Usage;
			if (string.IsNullOrWhiteSpace(text))
			{
				IEnumerable<string> values = command.Parameters.Select((ParameterInfo p) => CommandRegistry.IsRemainderParameter(p) ? ("<" + p.Name + "...>").Color(Color.LightGrey) : ((!p.HasDefaultValue) ? ("(" + p.Name + ")").Color(Color.LightGrey) : $"[{p.Name}={p.DefaultValue}]".Color(Color.Green)));
				text = string.Join(" ", values);
			}
			return (!string.IsNullOrWhiteSpace(text)) ? (" " + text) : string.Empty;
		}
	}
	public static class RepeatCommands
	{
		[Command("!", null, null, "Repeats the most recently executed command", null, false)]
		public static void RepeatLastCommand(ICommandContext ctx)
		{
			ctx.Error("This command is only a placeholder for the help system.");
		}

		[Command("! list", "! l", null, "Lists up to the last 10 commands you used.", null, false)]
		public static void ListCommandHistory(ICommandContext ctx)
		{
			ctx.Error("This command is only a placeholder for the help system.");
		}

		[Command("!", null, null, "Executes a specific command from your history by its number", null, false)]
		public static void ExecuteHistoryCommand(ICommandContext ctx, int previousXCommand)
		{
			ctx.Error("This command is only a placeholder for the help system.");
		}
	}
	internal static class VersionCommands
	{
		[Command("version", null, null, "Lists all installed plugins and their versions", null, true)]
		public static void VersionCommand(ICommandContext ctx)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Entity userEntity = (Entity)((ctx is ChatCommandContext chatCommandContext) ? chatCommandContext.Event.SenderUserEntity : default(Entity));
			VersionChecker.ListAllPluginVersions(userEntity);
		}
	}
}
namespace VCF.Core.Basics
{
	public class BasicAdminCheck : CommandMiddleware
	{
		public override bool CanExecute(ICommandContext ctx, CommandAttribute cmd, MethodInfo m)
		{
			return !cmd.AdminOnly || ctx.IsAdmin;
		}
	}
	public class RolePermissionMiddleware : CommandMiddleware
	{
		public override bool CanExecute(ICommandContext ctx, CommandAttribute command, MethodInfo method)
		{
			if (ctx.IsAdmin)
			{
				return true;
			}
			RoleRepository service = ctx.Services.GetService<RoleRepository>();
			return service.CanUserExecuteCommand(ctx.Name, command.Id);
		}
	}
	public interface IRoleStorage
	{
		HashSet<string> Roles { get; }

		void SetCommandPermission(string command, HashSet<string> roleIds);

		void SetUserRoles(string userId, HashSet<string> roleIds);

		HashSet<string> GetCommandPermission(string command);

		HashSet<string> GetUserRoles(string userId);
	}
	public class RoleRepository
	{
		private IRoleStorage _storage;

		public HashSet<string> Roles => _storage.Roles;

		public RoleRepository(IRoleStorage storage)
		{
			_storage = storage;
		}

		public void AddUserToRole(string user, string role)
		{
			HashSet<string> hashSet = _storage.GetUserRoles(user) ?? new HashSet<string>();
			hashSet.Add(role);
			_storage.SetUserRoles(user, hashSet);
		}

		public void RemoveUserFromRole(string user, string role)
		{
			HashSet<string> hashSet = _storage.GetUserRoles(user) ?? new HashSet<string>();
			hashSet.Remove(role);
			_storage.SetUserRoles(user, hashSet);
		}

		public void AddRoleToCommand(string command, string role)
		{
			HashSet<string> hashSet = _storage.GetCommandPermission(command) ?? new HashSet<string>();
			hashSet.Add(role);
			_storage.SetCommandPermission(command, hashSet);
		}

		public void RemoveRoleFromCommand(string command, string role)
		{
			HashSet<string> hashSet = _storage.GetCommandPermission(command) ?? new HashSet<string>();
			hashSet.Remove(role);
			_storage.SetCommandPermission(command, hashSet);
		}

		public HashSet<string> ListUserRoles(string user)
		{
			return _storage.GetUserRoles(user);
		}

		public HashSet<string> ListCommandRoles(string command)
		{
			return _storage.GetCommandPermission(command);
		}

		public bool CanUserExecuteCommand(string user, string command)
		{
			HashSet<string> commandPermission = _storage.GetCommandPermission(command);
			if (commandPermission == null)
			{
				return false;
			}
			HashSet<string> userRoles = _storage.GetUserRoles(user);
			if (userRoles == null)
			{
				return false;
			}
			return commandPermission.Any(userRoles.Contains);
		}
	}
	public class MemoryRoleStorage : IRoleStorage
	{
		private Dictionary<string, HashSet<string>> _userRoles = new Dictionary<string, HashSet<string>>();

		private Dictionary<string, HashSet<string>> _commandPermissions = new Dictionary<string, HashSet<string>>();

		public HashSet<string> Roles => new HashSet<string>();

		public void SetCommandPermission(string command, HashSet<string> roleIds)
		{
			foreach (string roleId in roleIds)
			{
				Roles.Add(roleId);
			}
			_commandPermissions[command] = roleIds;
		}

		public void SetUserRoles(string userId, HashSet<string> roleIds)
		{
			_userRoles[userId] = roleIds;
		}

		public HashSet<string> GetCommandPermission(string command)
		{
			return _commandPermissions.GetValueOrDefault(command);
		}

		public HashSet<string> GetUserRoles(string userId)
		{
			HashSet<string> value;
			return _userRoles.TryGetValue(userId, out value) ? value : new HashSet<string>();
		}
	}
	public class RoleCommands
	{
		public record struct Role(string Name);

		public record struct User(string Id);

		public record struct Command(string Id);

		public class RoleConverter : CommandArgumentConverter<Role>
		{
			public override Role Parse(ICommandContext ctx, string input)
			{
				RoleRepository requiredService = ctx.Services.GetRequiredService<RoleRepository>();
				if (requiredService.Roles.Contains(input))
				{
					return new Role(input);
				}
				throw ctx.Error("Invalid role");
			}
		}

		public class UserConverter : CommandArgumentConverter<User>
		{
			public override User Parse(ICommandContext ctx, string input)
			{
				return new User(input);
			}
		}

		private RoleRepository _roleRepository = new RoleRepository(new MemoryRoleStorage());

		[Command("create", null, null, null, null, false)]
		public void CreateRole(ICommandContext ctx, s