209 lines
5.8 KiB
C#
209 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using ReallifeGamemode.Server.Core.API;
|
|
using ReallifeGamemode.Server.Types;
|
|
using ReallifeGamemode.Server.Common;
|
|
using ReallifeGamemode.Server.Log;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace ReallifeGamemode.Server.Core.Commands
|
|
{
|
|
class CommandHandler
|
|
{
|
|
private readonly Dictionary<string, Command> registeredCommands = new Dictionary<string, Command>();
|
|
private readonly ILogger logger = LogManager.GetLogger<CommandHandler>();
|
|
|
|
private readonly IAPI api;
|
|
private readonly string[] legacyCommands;
|
|
private Random random = new Random();
|
|
|
|
public CommandHandler(IAPI api, string[] registeredCommands)
|
|
{
|
|
this.api = api;
|
|
legacyCommands = registeredCommands;
|
|
Main.EventHandler.RegisterClientEvent("Command", OnPlayerCommand);
|
|
}
|
|
|
|
private void OnPlayerCommand(IPlayer player, object[] args)
|
|
{
|
|
var command = (args.First() as string)?.ToString()?.ToLower();
|
|
|
|
logger.LogInformation("Player '{Name}' executed command '{command}'", player.Name, command);
|
|
|
|
if (legacyCommands.Contains(command))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!registeredCommands.ContainsKey(command))
|
|
{
|
|
player.SendMessage($"Der Befehl ~b~/{command}~s~ existiert nicht", ChatPrefix.Error);
|
|
return;
|
|
}
|
|
|
|
var executor = registeredCommands[command];
|
|
|
|
if (!executor.CanExecute(player))
|
|
{
|
|
player.SendMessage($"Du darfst diesen Befehl nicht ausführen", ChatPrefix.Error);
|
|
return;
|
|
}
|
|
|
|
var methodInfo = executor.GetType().GetMethod("Handle");
|
|
|
|
var arguments = new List<object>
|
|
{
|
|
player
|
|
};
|
|
|
|
try
|
|
{
|
|
arguments.AddRange(ComputeParameters(methodInfo, args.Skip(1).ToArray()));
|
|
|
|
var result = methodInfo.Invoke(executor, arguments.ToArray());
|
|
}
|
|
catch (ArgumentException ex)
|
|
{
|
|
player.SendMessage($"Der Parameter ~y~'{ex.Message}'~s~ ist ungültig.", ChatPrefix.Error);
|
|
}
|
|
catch (SendHelpTextException)
|
|
{
|
|
player.SendMessage("/" + command + " " + executor.HelpText, ChatPrefix.Usage);
|
|
}
|
|
catch (TargetInvocationException ex)
|
|
{
|
|
var errorCode = GetNewErrorCode();
|
|
ex.Data.Add("ErrorCode", errorCode);
|
|
logger.LogError(ex, "Error (Code: {ErrorCode}) while executing command '{Command}' from user '{Name}'", errorCode, command, player.Name);
|
|
player.SendMessage($"Bei der Ausführung des Befehls gab es einen unbekannten Fehler. ~m~({errorCode})", ChatPrefix.Error);
|
|
}
|
|
}
|
|
|
|
public void RegisterCommand(string command, Command commandExecutor)
|
|
{
|
|
command = command.ToLower();
|
|
logger.LogDebug("Adding command '{command}'", command);
|
|
|
|
if (command.IsNullOrEmpty())
|
|
{
|
|
logger.LogError("Command name is null");
|
|
return;
|
|
}
|
|
|
|
if (commandExecutor == null)
|
|
{
|
|
logger.LogError("Command executor for command '{command}' is null", command);
|
|
return;
|
|
}
|
|
|
|
var methodInfo = commandExecutor.GetType().GetMethod("Handle");
|
|
|
|
if (methodInfo == null)
|
|
{
|
|
logger.LogError("The executor for command '{command}' does not have a 'Handle' Method", command);
|
|
return;
|
|
}
|
|
|
|
registeredCommands[command] = commandExecutor;
|
|
}
|
|
|
|
private object[] ComputeParameters(MethodInfo methodInfo, object[] arguments)
|
|
{
|
|
var computedParameters = new List<object>();
|
|
|
|
var parameterInfos = methodInfo.GetParameters();
|
|
var parameterCount = parameterInfos.Length - 1;
|
|
|
|
var argumentCount = arguments.Length;
|
|
|
|
for (var i = 1; i <= parameterCount; i++)
|
|
{
|
|
var currentParameter = parameterInfos[i];
|
|
|
|
var parameterType = currentParameter.ParameterType;
|
|
|
|
object currentArgument;
|
|
|
|
if (i < argumentCount + 1)
|
|
{
|
|
currentArgument = arguments[i - 1];
|
|
}
|
|
else if (argumentCount <= (i - 1) && currentParameter.HasDefaultValue)
|
|
{
|
|
currentArgument = currentParameter.DefaultValue;
|
|
computedParameters.Add(currentArgument);
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
throw new CommandArgumentCountMismatchException();
|
|
}
|
|
|
|
if (parameterType == typeof(IPlayer))
|
|
{
|
|
var player = api.GetPlayerFromNameOrId(currentArgument.ToString());
|
|
|
|
if (player == null)
|
|
{
|
|
throw new ArgumentException($"Der Spieler wurde nicht gefunden.");
|
|
}
|
|
|
|
computedParameters.Add(player);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (parameterType == typeof(string))
|
|
{
|
|
if (i == parameterCount)
|
|
{
|
|
var str = string.Join(' ', arguments.Skip(i - 1));
|
|
computedParameters.Add(str);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
computedParameters.Add(currentArgument);
|
|
}
|
|
}
|
|
|
|
if (parameterType.IsEnum)
|
|
{
|
|
var stringArg = currentArgument.ToString();
|
|
if (stringArg.TryParseEnum(parameterType, out var result))
|
|
{
|
|
computedParameters.Add(result);
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException(currentArgument.ToString());
|
|
}
|
|
}
|
|
else if (parameterType.IsPrimitive)
|
|
{
|
|
try
|
|
{
|
|
computedParameters.Add(Convert.ChangeType(currentArgument, parameterType));
|
|
}
|
|
catch
|
|
{
|
|
throw new ArgumentException(currentArgument.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
return computedParameters.ToArray();
|
|
}
|
|
|
|
private string GetNewErrorCode()
|
|
{
|
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#?$";
|
|
return new string(Enumerable.Repeat(chars, 6)
|
|
.Select(s => s[random.Next(s.Length)]).ToArray());
|
|
}
|
|
}
|
|
}
|