Begin script abstraction
This commit is contained in:
202
ReallifeGamemode.Server.Core/Commands/CommandHandler.cs
Normal file
202
ReallifeGamemode.Server.Core/Commands/CommandHandler.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
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 Random random = new Random();
|
||||
|
||||
public CommandHandler(IAPI api)
|
||||
{
|
||||
this.api = api;
|
||||
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 (!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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user