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