Decompiled source of VampireCommandFramework v0.9.0

VampireCommandFramework.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
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 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.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.9.0.0")]
[assembly: AssemblyInformationalVersion("0.9.0+24.Branch.main.Sha.d432c15d766e8a2dc2260b16d84a5c4dc4882c7e")]
[assembly: AssemblyProduct("VampireCommandFramework")]
[assembly: AssemblyTitle("VampireCommandFramework")]
[assembly: InternalsVisibleTo("VCF.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.9.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_0025: 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)
			if (v.Length > maxMessageLength)
			{
				v = v.Substring(0, maxMessageLength);
			}
			ServerChatUtils.SendSystemMessageToClient(VWorld.Server.EntityManager, User, v);
		}

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

		public static string Primary = "#b0b";

		public static string White = "#eee";

		public static string LightGrey = "#ccc";

		public static string Yellow = "#dd0";

		public static string DarkGreen = "#0c0";
	}
	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; }
	}
	[BepInPlugin("gg.deca.VampireCommandFramework", "VampireCommandFramework", "0.9.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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: 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();
			CommandRegistry.RegisterCommandType(typeof(HelpCommands));
			CommandRegistry.RegisterCommandType(typeof(BepInExConfigCommands));
			((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 = ".";

		private 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()
		};

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


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


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

		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} {value}");
					return false;
				}
			}
			return true;
		}

		public static CommandResult Handle(ICommandContext ctx, string input)
		{
			CacheResult command2 = _cache.GetCommand(input);
			CommandMetadata command3 = command2.Command;
			string[] args = command2.Args;
			CommandMetadata commandMetadata = command3;
			string[] array = args;
			if (!command2.IsMatched)
			{
				if (!command2.HasPartial)
				{
					return CommandResult.Unmatched;
				}
				foreach (CommandMetadata partialMatch in command2.PartialMatches)
				{
					ctx.SysReply(HelpCommands.PrintShortHelp(partialMatch));
				}
				return CommandResult.UsageError;
			}
			if (!commandMetadata.ContextType.IsAssignableFrom(ctx?.GetType()))
			{
				Log.Warning($"Matched [{commandMetadata.Attribute.Id}] but can not assign {commandMetadata.ContextType.Name} from {ctx?.GetType().Name}");
				return CommandResult.InternalError;
			}
			if (commandMetadata.Constructor != null && !commandMetadata.ConstructorType.IsAssignableFrom(ctx?.GetType()))
			{
				Log.Warning($"Matched [{commandMetadata.Attribute.Id}] but can not assign {commandMetadata.ConstructorType.Name} from {ctx?.GetType().Name}");
				ctx.InternalError();
				return CommandResult.InternalError;
			}
			int num = array.Length;
			int num2 = commandMetadata.Parameters.Length;
			object[] array2 = new object[num2 + 1];
			array2[0] = ctx;
			if (num != num2)
			{
				if (!commandMetadata.Parameters.Skip(num).All((ParameterInfo p) => p.HasDefaultValue))
				{
					return CommandResult.UsageError;
				}
				for (int i = num; i < num2; i++)
				{
					array2[i + 1] = commandMetadata.Parameters[i].DefaultValue;
				}
			}
			for (int j = 0; j < num; j++)
			{
				ParameterInfo parameterInfo = commandMetadata.Parameters[j];
				string text = array[j];
				if (_converters.TryGetValue(parameterInfo.ParameterType, out (object, MethodInfo, Type) value))
				{
					var (obj, methodInfo, type) = value;
					if (!type.IsAssignableFrom(ctx.GetType()))
					{
						Log.Error("Converter type " + type.Name + " is not assignable from " + ctx.GetType().Name);
						ctx.InternalError();
						return CommandResult.InternalError;
					}
					object[] parameters = new object[2] { ctx, text };
					try
					{
						object obj2 = methodInfo.Invoke(obj, parameters);
						array2[j + 1] = obj2;
					}
					catch (TargetInvocationException ex)
					{
						if (ex.InnerException is CommandException ex2)
						{
							ctx.Reply("<color=red>[error]</color> Failed converted parameter: " + ex2.Message);
							return CommandResult.UsageError;
						}
						Log.Warning($"Hit unexpected exception {ex}");
						ctx.InternalError();
						return CommandResult.InternalError;
					}
					catch (Exception value2)
					{
						Log.Warning($"Hit unexpected exception {value2}");
						ctx.InternalError();
						return CommandResult.InternalError;
					}
					continue;
				}
				TypeConverter converter = TypeDescriptor.GetConverter(parameterInfo.ParameterType);
				try
				{
					object obj3 = converter.ConvertFromInvariantString(text);
					if (converter is EnumConverter && !Enum.IsDefined(parameterInfo.ParameterType, obj3))
					{
						ctx.Reply($"<color=red>[error]</color> Invalid value {obj3} for {parameterInfo.ParameterType.Name}");
						return CommandResult.UsageError;
					}
					array2[j + 1] = obj3;
				}
				catch (Exception ex3)
				{
					ctx.Reply("<color=red>[error]</color> Failed converted parameter: " + ex3.Message);
					return CommandResult.UsageError;
				}
			}
			object obj4 = null;
			if (!commandMetadata.Method.IsStatic && (!commandMetadata.Method.DeclaringType.IsAbstract || !commandMetadata.Method.DeclaringType.IsSealed))
			{
				try
				{
					object? obj5;
					if (!(commandMetadata.Constructor == null))
					{
						ConstructorInfo constructor = commandMetadata.Constructor;
						object[] parameters2 = new ICommandContext[1] { ctx };
						obj5 = constructor.Invoke(parameters2);
					}
					else
					{
						obj5 = Activator.CreateInstance(commandMetadata.Method.DeclaringType);
					}
					obj4 = obj5;
				}
				catch (TargetInvocationException ex4)
				{
					if (ex4.InnerException is CommandException ex5)
					{
						ctx.SysReply(ex5.Message);
					}
					else
					{
						ctx.InternalError();
					}
					return CommandResult.InternalError;
				}
			}
			if (!CanCommandExecute(ctx, commandMetadata))
			{
				ctx.Reply("<color=red>[denied]</color> " + commandMetadata.Attribute.Id);
				return CommandResult.Denied;
			}
			HandleBeforeExecute(ctx, commandMetadata);
			CommandException ex7 = default(CommandException);
			try
			{
				commandMetadata.Method.Invoke(obj4, array2);
			}
			catch (TargetInvocationException ex6) when (((Func<bool>)delegate
			{
				// Could not convert BlockContainer to single expression
				ex7 = ex6.InnerException as CommandException;
				return ex7 != null;
			}).Invoke())
			{
				ctx.Reply("<color=red>[error]</color> " + ex7.Message);
				return CommandResult.CommandError;
			}
			catch (Exception value3)
			{
				Log.Warning($"Hit unexpected exception executing command {commandMetadata.Attribute.Id}\n: {value3}");
				ctx.InternalError();
				return CommandResult.InternalError;
			}
			HandleAfterExecute(ctx, commandMetadata);
			return CommandResult.Success;
			static void HandleAfterExecute(ICommandContext ctx, CommandMetadata command)
			{
				Middlewares.ForEach(delegate(CommandMiddleware m)
				{
					m.AfterExecute(ctx, command.Attribute, command.Method);
				});
			}
			static void HandleBeforeExecute(ICommandContext ctx, CommandMetadata command)
			{
				Middlewares.ForEach(delegate(CommandMiddleware m)
				{
					m.BeforeExecute(ctx, command.Attribute, command.Method);
				});
			}
		}

		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);
				}
				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);
				}
			}
		}

		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 + " has no CommandContext as first argument");
				return;
			}
			ParameterInfo[] array = parameters.Skip(1).ToArray();
			if (!array.All(delegate(ParameterInfo param)
			{
				if (_converters.ContainsKey(param.ParameterType))
				{
					Log.Debug($"Method {method.Name} has a parameter of type {param.ParameterType.Name} 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} could not be converted, so {method.Name} will be ignored.");
					return false;
				}
				return true;
			}))
			{
				return;
			}
			Type constructorType = customConstructor?.GetParameters().Single().ParameterType;
			CommandMetadata commandMetadata = new CommandMetadata(customAttribute, 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);
				}
			}
			AssemblyCommandMap.TryGetValue(assembly, out var value);
			if (value == null)
			{
				value = new Dictionary<CommandMetadata, List<string>>();
			}
			value[commandMetadata] = list;
			AssemblyCommandMap[assembly] = value;
		}

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

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

		public const string PLUGIN_NAME = "VampireCommandFramework";

		public const string PLUGIN_VERSION = "0.9.0";
	}
}
namespace VampireCommandFramework.Registry
{
	internal record CacheResult(CommandMetadata Command, string[] Args, IEnumerable<CommandMetadata> PartialMatches)
	{
		internal bool IsMatched => Command != null;

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

		[CompilerGenerated]
		protected virtual bool PrintMembers(StringBuilder builder)
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			builder.Append("Command = ");
			builder.Append(Command);
			builder.Append(", Args = ");
			builder.Append(Args);
			builder.Append(", PartialMatches = ");
			builder.Append(PartialMatches);
			return true;
		}
	}
	internal class CommandCache
	{
		private static Dictionary<Type, HashSet<(string, int)>> _commandAssemblyMap = new Dictionary<Type, HashSet<(string, int)>>();

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

		internal void AddCommand(string key, ParameterInfo[] parameters, CommandMetadata command)
		{
			int num = parameters.Length;
			int num2 = parameters.Where((ParameterInfo p) => p.HasDefaultValue).Count();
			if (!_newCache.ContainsKey(key))
			{
				_newCache.Add(key, new Dictionary<int, CommandMetadata>());
			}
			for (int i = num - num2; i <= num; i++)
			{
				_newCache[key] = _newCache.GetValueOrDefault(key, new Dictionary<int, CommandMetadata>()) ?? new Dictionary<int, CommandMetadata>();
				if (_newCache[key].ContainsKey(i))
				{
					Log.Warning($"Command {key} has multiple commands with {i} parameters");
				}
				else
				{
					_newCache[key][i] = 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, i));
					_commandAssemblyMap[declaringType] = hashSet;
				}
			}
		}

		internal CacheResult GetCommand(string rawInput)
		{
			List<CommandMetadata> list = new List<CommandMetadata>();
			foreach (var (text2, dictionary2) in _newCache)
			{
				if (rawInput.StartsWith(text2) && (rawInput.Length <= text2.Length || rawInput[text2.Length] == ' '))
				{
					string input = rawInput.Substring(text2.Length).Trim();
					string[] array = Utility.GetParts(input).ToArray();
					if (dictionary2.TryGetValue(array.Length, out var value))
					{
						return new CacheResult(value, array, null);
					}
					list.AddRange(dictionary2.Values);
				}
			}
			return new CacheResult(null, null, list.Distinct());
		}

		internal void RemoveCommandsFromType(Type t)
		{
			if (!_commandAssemblyMap.TryGetValue(t, out var value))
			{
				return;
			}
			foreach (var (key, key2) in value)
			{
				if (_newCache.TryGetValue(key, out var value2))
				{
					value2.Remove(key2);
				}
			}
			_commandAssemblyMap.Remove(t);
		}

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

		internal void Reset()
		{
			throw new NotImplementedException();
		}
	}
	internal record CommandMetadata(CommandAttribute Attribute, MethodInfo Method, ConstructorInfo Constructor, ParameterInfo[] Parameters, Type ContextType, Type ConstructorType, CommandGroupAttribute GroupAttribute);
}
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.White));
		}

		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(Environment.NewLine);
			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();
		}
	}
}
namespace VampireCommandFramework.Breadstone
{
	[HarmonyPriority(200)]
	[HarmonyBefore(new string[] { "gg.deca.Bloodstone" })]
	[HarmonyPatch(typeof(ChatMessageSystem), "OnUpdate")]
	public static class ChatMessageSystem_Patch
	{
		public static bool Prefix(ChatMessageSystem __instance)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			_ = __instance.__query_661171423_0;
			if (true)
			{
				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();
					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);
						return true;
					}
					if (commandResult != 0)
					{
						entityManager = VWorld.Server.EntityManager;
						((EntityManager)(ref entityManager)).DestroyEntity(current);
						return true;
					}
				}
			}
			return true;
		}
	}
	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_0006: 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)
			ServerChatUtils.SendSystemMessageToClient(Server.EntityManager, user, message);
		}

		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.White));
					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)
		{
			if (!string.IsNullOrEmpty(search))
			{
				KeyValuePair<Assembly, Dictionary<CommandMetadata, List<string>>> assembly2 = CommandRegistry.AssemblyCommandMap.FirstOrDefault((KeyValuePair<Assembly, Dictionary<CommandMetadata, List<string>>> x) => x.Key.GetName().Name.StartsWith(search, StringComparison.OrdinalIgnoreCase));
				if (assembly2.Value != null)
				{
					StringBuilder stringBuilder = new StringBuilder();
					PrintAssemblyHelp(ctx, assembly2, stringBuilder);
					ctx.SysPaginatedReply(stringBuilder);
					return;
				}
				IEnumerable<KeyValuePair<CommandMetadata, List<string>>> source = CommandRegistry.AssemblyCommandMap.SelectMany((KeyValuePair<Assembly, 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.Value.Contains<string>(search, StringComparer.InvariantCultureIgnoreCase));
				source2 = source2.Where((KeyValuePair<CommandMetadata, List<string>> kvp) => CommandRegistry.CanCommandExecute(ctx, kvp.Key));
				if (!source2.Any())
				{
					throw ctx.Error("Could not find any commands for \"" + search + "\"");
				}
				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.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(17, 1, stringBuilder4);
			handler.AppendLiteral("Listing ");
			handler.AppendFormatted(Format.B("all"));
			handler.AppendLiteral(" commands");
			stringBuilder4.AppendLine(ref handler);
			foreach (KeyValuePair<Assembly, Dictionary<CommandMetadata, List<string>>> item3 in CommandRegistry.AssemblyCommandMap)
			{
				PrintAssemblyHelp(ctx, item3, stringBuilder3);
			}
			ctx.SysPaginatedReply(stringBuilder3);
			static void GenerateFullHelp(CommandMetadata command, List<string> aliases, StringBuilder sb)
			{
				StringBuilder stringBuilder5 = sb;
				StringBuilder stringBuilder6 = stringBuilder5;
				StringBuilder.AppendInterpolatedStringHandler handler2 = new StringBuilder.AppendInterpolatedStringHandler(4, 3, stringBuilder5);
				handler2.AppendFormatted(Format.B(command.Attribute.Name));
				handler2.AppendLiteral(" (");
				handler2.AppendFormatted(command.Attribute.Id);
				handler2.AppendLiteral(") ");
				handler2.AppendFormatted(command.Attribute.Description);
				stringBuilder6.AppendLine(ref handler2);
				sb.AppendLine(PrintShortHelp(command));
				stringBuilder5 = sb;
				StringBuilder stringBuilder7 = stringBuilder5;
				handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder5);
				handler2.AppendFormatted(Format.B("Aliases").Underline());
				handler2.AppendLiteral(": ");
				handler2.AppendFormatted(string.Join(", ", aliases).Italic());
				stringBuilder7.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)
				{
					stringBuilder5 = sb;
					StringBuilder stringBuilder8 = stringBuilder5;
					handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder5);
					handler2.AppendFormatted((item4.Name + " Values").Bold().Underline());
					handler2.AppendLiteral(": ");
					handler2.AppendFormatted(string.Join(", ", Enum.GetNames(item4)));
					stringBuilder8.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;
						stringBuilder5 = sb;
						StringBuilder stringBuilder9 = stringBuilder5;
						handler2 = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder5);
						handler2.AppendFormatted((item5.Name ?? "").Bold());
						handler2.AppendLiteral(": ");
						handler2.AppendFormatted(converterUsage.Usage);
						stringBuilder9.AppendLine(ref handler2);
					}
				}
			}
			static void PrintAssemblyHelp(ICommandContext ctx, KeyValuePair<Assembly, Dictionary<CommandMetadata, List<string>>> assembly, StringBuilder sb)
			{
				string name = assembly.Key.GetName().Name;
				name = _trailingLongDashRegex.Replace(name, "");
				sb.AppendLine(("Commands from " + name.Medium().Color(Color.Primary) + ":").Underline());
				IEnumerable<CommandMetadata> enumerable3 = assembly.Value.Keys.Where((CommandMetadata c) => CommandRegistry.CanCommandExecute(ctx, c));
				foreach (CommandMetadata item6 in enumerable3)
				{
					sb.AppendLine(PrintShortHelp(item6));
				}
			}
		}

		internal static string PrintShortHelp(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.White);
			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) => (!p.HasDefaultValue) ? ("(" + p.Name + ")").Color(Color.LightGrey) : $"[{p.Name}={p.DefaultValue}]".Color(Color.DarkGreen));
				text = string.Join(" ", values);
			}
			return (!string.IsNullOrWhiteSpace(text)) ? (" " + text) : string.Empty;
		}
	}
}
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, string name)
		{
			_roleRepository.Roles.Add(name);
		}

		[Command("allow", null, null, null, null, false)]
		public void AllowCommand(ICommandContext ctx, Role role, Command command)
		{
			_roleRepository.AddRoleToCommand(command.Id, role.Name);
		}

		[Command("deny", null, null, null, null, false)]
		public void DenyCommand(ICommandContext ctx, Role role, Command command)
		{
			_roleRepository.RemoveRoleFromCommand(command.Id, role.Name);
		}

		[Command("assign", null, null, null, null, false)]
		public void AssignUserToRole(ICommandContext ctx, User user, Role role)
		{
			_roleRepository.AddUserToRole(user.Id, role.Name);
		}

		[Command("unassign", null, null, null, null, false)]
		public void UnassignUserFromRole(ICommandContext ctx, User user, Role role)
		{
			_roleRepository.RemoveUserFromRole(user.Id, role.Name);
		}

		[Command("list", null, null, null, null, false)]
		public void ListRoles(ICommandContext ctx)
		{
			ctx.Reply("Roles: " + string.Join(", ", _roleRepository.Roles));
		}

		[Command("list user", null, null, null, null, false)]
		public void ListRoles(ICommandContext ctx, User user)
		{
			ctx.Reply("Roles: " + string.Join(", ", _roleRepository.ListUserRoles(user.Id)));
		}

		[Command("list command", null, null, null, null, false)]
		public void ListCommands(ICommandContext ctx, Command command)
		{
			ctx.Reply("Roles: " + string.Join(", ", _roleRepository.ListCommandRoles(command.Id)));
		}
	}
}