Core/Commands: Change way we handle optional args. Fixes #43
This commit is contained in:
@@ -26,30 +26,35 @@ namespace Game.Chat
|
||||
{
|
||||
class CommandArgs
|
||||
{
|
||||
public static object[] Parse(CommandHandler handler, Type[] parameterTypes, StringArguments args)
|
||||
public static bool Parse(out dynamic[] parsedArgs, CommandHandler handler, Type[] parameterTypes, StringArguments args)
|
||||
{
|
||||
List<object> arguments = new();
|
||||
arguments.Add(handler);
|
||||
for (var i = 1; i < parameterTypes.Length; i++)
|
||||
arguments.Add(default);
|
||||
parsedArgs = new dynamic[parameterTypes.Length];
|
||||
parsedArgs[0] = handler;
|
||||
|
||||
for (var i = 1; i < parameterTypes.Length; i++)
|
||||
{
|
||||
if (!ParseArgument(out dynamic value, parameterTypes[i], args))
|
||||
break;
|
||||
return false;
|
||||
|
||||
arguments[i] = value;
|
||||
parsedArgs[i] = value;
|
||||
}
|
||||
|
||||
return arguments.ToArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseArgument(out dynamic value, Type type, StringArguments args)
|
||||
static bool ParseArgument(out dynamic value, Type type, StringArguments args, bool IsOptional = false)
|
||||
{
|
||||
value = default;
|
||||
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(OptionalArg<>))
|
||||
return ParseArgument(out value, type.GetGenericArguments()[0], args, true);
|
||||
|
||||
//todo remove me when all commands to changed to OptionalArg<T>
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
return ParseArgument(out value, Nullable.GetUnderlyingType(type), args, true);
|
||||
|
||||
if (args.IsAtEnd())
|
||||
return false;
|
||||
return IsOptional;
|
||||
|
||||
if (Hyperlink.TryParse(out value, type, args))
|
||||
return true;
|
||||
@@ -57,9 +62,6 @@ namespace Game.Chat
|
||||
if (type.IsEnum)
|
||||
type = type.GetEnumUnderlyingType();
|
||||
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
type = Nullable.GetUnderlyingType(type);
|
||||
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
@@ -258,4 +260,53 @@ namespace Game.Chat
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
struct OptionalArg<T>
|
||||
{
|
||||
private bool _hasValue;
|
||||
public T Value;
|
||||
|
||||
public OptionalArg(T value)
|
||||
{
|
||||
Value = value;
|
||||
_hasValue = true;
|
||||
}
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get { return _hasValue; }
|
||||
}
|
||||
|
||||
public void Set(T value)
|
||||
{
|
||||
Value = value;
|
||||
_hasValue = true;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_hasValue = false;
|
||||
Value = default;
|
||||
}
|
||||
|
||||
public T ValueOr(T otherValue)
|
||||
{
|
||||
return HasValue ? Value : otherValue;
|
||||
}
|
||||
|
||||
public static explicit operator T(OptionalArg<T> optional)
|
||||
{
|
||||
return optional.Value;
|
||||
}
|
||||
|
||||
public static implicit operator OptionalArg<T>(T value)
|
||||
{
|
||||
return new OptionalArg<T>(value);
|
||||
}
|
||||
|
||||
public Type GetValueType()
|
||||
{
|
||||
return typeof(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +220,7 @@ namespace Game.Chat
|
||||
|
||||
if (cmd != null)
|
||||
{ /* if we matched a command at some point, invoke it */
|
||||
handler._sentErrorMessage = false;
|
||||
if (cmd.IsInvokerVisible(handler) && cmd.Invoke(handler, new StringArguments(oldTail)))
|
||||
{ /* invocation succeeded, log this */
|
||||
if (!handler.IsConsole())
|
||||
@@ -403,8 +404,12 @@ namespace Game.Chat
|
||||
if (parameterTypes.Contains(typeof(StringArguments)))//Old system, can remove once all commands are changed.
|
||||
return (bool)_methodInfo.Invoke(null, new object[] { handler, args });
|
||||
else
|
||||
return (bool)_methodInfo.Invoke(null, CommandArgs.Parse(handler, parameterTypes, args));
|
||||
{
|
||||
if (CommandArgs.Parse(out dynamic[] parseArgs, handler, parameterTypes, args))
|
||||
return (bool)_methodInfo.Invoke(null, parseArgs);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("create", CypherStrings.CommandAccCreateHelp, RBACPermissions.CommandAccountCreate, true)]
|
||||
static bool HandleAccountCreateCommand(CommandHandler handler, string accountName, string password, string email)
|
||||
static bool HandleAccountCreateCommand(CommandHandler handler, string accountName, string password, OptionalArg<string> email)
|
||||
{
|
||||
if (accountName.Contains("@"))
|
||||
{
|
||||
@@ -95,7 +95,7 @@ namespace Game.Chat
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.CreateAccount(accountName, password, email);
|
||||
AccountOpResult result = Global.AccountMgr.CreateAccount(accountName, password, email.ValueOr(""));
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
|
||||
@@ -733,10 +733,10 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[CommandNonGroup("help", RBACPermissions.CommandHelp, true)]
|
||||
static bool HandleHelpCommand(CommandHandler handler, string cmd)
|
||||
static bool HandleHelpCommand(CommandHandler handler, OptionalArg<string> cmd)
|
||||
{
|
||||
ChatCommandNode.SendCommandHelpFor(handler, cmd);
|
||||
if (cmd.IsEmpty())
|
||||
ChatCommandNode.SendCommandHelpFor(handler, cmd.ValueOr(""));
|
||||
if (!cmd.HasValue)
|
||||
ChatCommandNode.SendCommandHelpFor(handler, "help");
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user