160 lines
5.4 KiB
C#
160 lines
5.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using NLog;
|
|
using Torch.API;
|
|
using Torch.API.Plugins;
|
|
using Torch.Commands.Permissions;
|
|
using VRage.Game;
|
|
using VRage.Game.ModAPI;
|
|
|
|
namespace Torch.Commands
|
|
{
|
|
public class Command
|
|
{
|
|
public MyPromoteLevel MinimumPromoteLevel { get; }
|
|
public string Name { get; }
|
|
public string Description { get; }
|
|
public string HelpText { get; }
|
|
public Type Module { get; }
|
|
public List<string> Path { get; } = new List<string>();
|
|
public ITorchPlugin Plugin { get; }
|
|
public string SyntaxHelp { get; }
|
|
|
|
private readonly MethodInfo _method;
|
|
private ParameterInfo[] _parameters;
|
|
private int? _requiredParamCount;
|
|
private static readonly Logger Log = LogManager.GetLogger(nameof(Command));
|
|
|
|
public Command(ITorchPlugin plugin, MethodInfo commandMethod)
|
|
{
|
|
Plugin = plugin;
|
|
|
|
var commandAttribute = commandMethod.GetCustomAttribute<CommandAttribute>();
|
|
if (commandAttribute == null)
|
|
throw new TypeLoadException($"Method does not have a {nameof(CommandAttribute)}");
|
|
|
|
var permissionAttribute = commandMethod.GetCustomAttribute<PermissionAttribute>();
|
|
MinimumPromoteLevel = permissionAttribute?.PromoteLevel ?? MyPromoteLevel.Admin;
|
|
|
|
if (!commandMethod.DeclaringType.IsSubclassOf(typeof(CommandModule)))
|
|
throw new TypeLoadException($"Command {commandMethod.Name}'s declaring type {commandMethod.DeclaringType.FullName} is not a subclass of {nameof(CommandModule)}");
|
|
|
|
var moduleAttribute = commandMethod.DeclaringType.GetCustomAttribute<CategoryAttribute>();
|
|
|
|
_method = commandMethod;
|
|
Module = commandMethod.DeclaringType;
|
|
|
|
if (moduleAttribute != null)
|
|
{
|
|
Path.AddRange(moduleAttribute.Path);
|
|
}
|
|
Path.AddRange(commandAttribute.Path);
|
|
|
|
Name = commandAttribute.Name;
|
|
Description = commandAttribute.Description;
|
|
HelpText = commandAttribute.HelpText;
|
|
|
|
//parameters
|
|
_parameters = commandMethod.GetParameters();
|
|
|
|
var sb = new StringBuilder();
|
|
sb.Append($"/{string.Join(" ", Path)} ");
|
|
for (var i = 0; i < _parameters.Length; i++)
|
|
{
|
|
var param = _parameters[i];
|
|
|
|
if (param.HasDefaultValue)
|
|
{
|
|
_requiredParamCount = _requiredParamCount ?? i;
|
|
|
|
sb.Append($"[{param.ParameterType.Name} {param.Name}] ");
|
|
}
|
|
else
|
|
{
|
|
sb.Append($"<{param.ParameterType.Name} {param.Name}> ");
|
|
}
|
|
}
|
|
|
|
_requiredParamCount = _requiredParamCount ?? _parameters.Length;
|
|
LogManager.GetLogger(nameof(Command)).Debug($"Params: {_parameters.Length} ({_requiredParamCount} required)");
|
|
SyntaxHelp = sb.ToString();
|
|
}
|
|
|
|
public bool TryInvoke(CommandContext context)
|
|
{
|
|
try
|
|
{
|
|
var parameters = new object[_parameters.Length];
|
|
|
|
if (context.Args.Count < _requiredParamCount)
|
|
return false;
|
|
|
|
//Convert args from string
|
|
for (var i = 0; i < _parameters.Length && i < context.Args.Count; i++)
|
|
{
|
|
if (context.Args[i].TryConvert(_parameters[i].ParameterType, out object obj))
|
|
parameters[i] = obj;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//Fill remaining parameters with default values
|
|
for (var i = 0; i < parameters.Length; i++)
|
|
{
|
|
if (parameters[i] == null)
|
|
parameters[i] = _parameters[i].DefaultValue;
|
|
}
|
|
|
|
var moduleInstance = (CommandModule)Activator.CreateInstance(Module);
|
|
moduleInstance.Context = context;
|
|
_method.Invoke(moduleInstance, parameters);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
context.Respond(e.Message, "Error", MyFontEnum.Red);
|
|
Log.Error($"Command '{SyntaxHelp}' from '{Plugin.Name ?? "Torch"}' threw an exception. Args: {string.Join(", ", context.Args)}");
|
|
Log.Error(e);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class Extensions
|
|
{
|
|
public static bool TryConvert(this string str, Type toType, out object val)
|
|
{
|
|
try
|
|
{
|
|
var converter = TypeDescriptor.GetConverter(toType);
|
|
val = converter.ConvertFromString(str);
|
|
return true;
|
|
}
|
|
catch (NotSupportedException)
|
|
{
|
|
val = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool TryConvert<T>(this string str, out T val)
|
|
{
|
|
try
|
|
{
|
|
var converter = TypeDescriptor.GetConverter(typeof(T));
|
|
val = (T)converter.ConvertFromString(str);
|
|
return true;
|
|
}
|
|
catch (NotSupportedException)
|
|
{
|
|
val = default(T);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|
|
} |