@@ -13,6 +13,7 @@ namespace Discord.Commands | |||||
private readonly object _instance; | private readonly object _instance; | ||||
private readonly Func<IMessage, IReadOnlyList<object>, Task> _action; | private readonly Func<IMessage, IReadOnlyList<object>, Task> _action; | ||||
public MethodInfo Source { get; } | |||||
public string Name { get; } | public string Name { get; } | ||||
public string Description { get; } | public string Description { get; } | ||||
public string Summary { get; } | public string Summary { get; } | ||||
@@ -21,25 +22,26 @@ namespace Discord.Commands | |||||
public IReadOnlyList<CommandParameter> Parameters { get; } | public IReadOnlyList<CommandParameter> Parameters { get; } | ||||
public IReadOnlyList<PreconditionAttribute> Preconditions { get; } | public IReadOnlyList<PreconditionAttribute> Preconditions { get; } | ||||
internal Command(Module module, object instance, CommandAttribute attribute, MethodInfo methodInfo, string groupPrefix) | |||||
internal Command(MethodInfo source, Module module, object instance, CommandAttribute attribute, string groupPrefix) | |||||
{ | { | ||||
Source = source; | |||||
Module = module; | Module = module; | ||||
_instance = instance; | _instance = instance; | ||||
Name = methodInfo.Name; | |||||
Name = source.Name; | |||||
Text = groupPrefix + attribute.Text; | Text = groupPrefix + attribute.Text; | ||||
var description = methodInfo.GetCustomAttribute<DescriptionAttribute>(); | |||||
var description = source.GetCustomAttribute<DescriptionAttribute>(); | |||||
if (description != null) | if (description != null) | ||||
Description = description.Text; | Description = description.Text; | ||||
var summary = methodInfo.GetCustomAttribute<SummaryAttribute>(); | |||||
var summary = source.GetCustomAttribute<SummaryAttribute>(); | |||||
if (summary != null) | if (summary != null) | ||||
Summary = summary.Text; | Summary = summary.Text; | ||||
Parameters = BuildParameters(methodInfo); | |||||
Preconditions = BuildPreconditions(methodInfo); | |||||
_action = BuildAction(methodInfo); | |||||
Parameters = BuildParameters(source); | |||||
Preconditions = BuildPreconditions(source); | |||||
_action = BuildAction(source); | |||||
} | } | ||||
public async Task<PreconditionResult> CheckPreconditions(IMessage context) | public async Task<PreconditionResult> CheckPreconditions(IMessage context) | ||||
@@ -135,7 +137,7 @@ namespace Discord.Commands | |||||
bool isOptional = parameter.IsOptional; | bool isOptional = parameter.IsOptional; | ||||
object defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null; | object defaultValue = parameter.HasDefaultValue ? parameter.DefaultValue : null; | ||||
paramBuilder.Add(new CommandParameter(name, summary, type, reader, isOptional, isRemainder, isMultiple, defaultValue)); | |||||
paramBuilder.Add(new CommandParameter(parameters[i], name, summary, type, reader, isOptional, isRemainder, isMultiple, defaultValue)); | |||||
} | } | ||||
return paramBuilder.ToImmutable(); | return paramBuilder.ToImmutable(); | ||||
} | } | ||||
@@ -1,5 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Reflection; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
@@ -9,19 +10,21 @@ namespace Discord.Commands | |||||
{ | { | ||||
private readonly TypeReader _reader; | private readonly TypeReader _reader; | ||||
public ParameterInfo Source { get; } | |||||
public string Name { get; } | public string Name { get; } | ||||
public string Summary { get; } | public string Summary { get; } | ||||
public bool IsOptional { get; } | public bool IsOptional { get; } | ||||
public bool IsRemainder { get; } | public bool IsRemainder { get; } | ||||
public bool IsMultiple { get; } | public bool IsMultiple { get; } | ||||
public Type Type { get; } | |||||
public Type ElementType { get; } | |||||
internal object DefaultValue { get; } | internal object DefaultValue { get; } | ||||
public CommandParameter(string name, string summary, Type type, TypeReader reader, bool isOptional, bool isRemainder, bool isMultiple, object defaultValue) | |||||
public CommandParameter(ParameterInfo source, string name, string summary, Type type, TypeReader reader, bool isOptional, bool isRemainder, bool isMultiple, object defaultValue) | |||||
{ | { | ||||
Source = source; | |||||
Name = name; | Name = name; | ||||
Summary = summary; | Summary = summary; | ||||
Type = type; | |||||
ElementType = type; | |||||
_reader = reader; | _reader = reader; | ||||
IsOptional = isOptional; | IsOptional = isOptional; | ||||
IsRemainder = isRemainder; | IsRemainder = isRemainder; | ||||
@@ -123,9 +123,9 @@ namespace Discord.Commands | |||||
if (curPos == endPos) | if (curPos == endPos) | ||||
{ | { | ||||
Array realParams = Array.CreateInstance(curParam.Type, paramsList.Count); | |||||
Array realParams = Array.CreateInstance(curParam.ElementType, paramsList.Count); | |||||
for (int i = 0; i < paramsList.Count; i++) | for (int i = 0; i < paramsList.Count; i++) | ||||
realParams.SetValue(Convert.ChangeType(paramsList[i], curParam.Type), i); | |||||
realParams.SetValue(Convert.ChangeType(paramsList[i], curParam.ElementType), i); | |||||
argList.Add(realParams); | argList.Add(realParams); | ||||
@@ -120,7 +120,7 @@ namespace Discord.Commands | |||||
if (_modules.ContainsKey(moduleInstance.GetType())) | if (_modules.ContainsKey(moduleInstance.GetType())) | ||||
return _modules[moduleInstance.GetType()]; | return _modules[moduleInstance.GetType()]; | ||||
var loadedModule = new Module(this, moduleInstance, moduleAttr, typeInfo); | |||||
var loadedModule = new Module(typeInfo, this, moduleInstance, moduleAttr); | |||||
_modules[moduleInstance.GetType()] = loadedModule; | _modules[moduleInstance.GetType()] = loadedModule; | ||||
foreach (var cmd in loadedModule.Commands) | foreach (var cmd in loadedModule.Commands) | ||||
@@ -8,6 +8,7 @@ namespace Discord.Commands | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class Module | public class Module | ||||
{ | { | ||||
public TypeInfo Source { get; } | |||||
public CommandService Service { get; } | public CommandService Service { get; } | ||||
public string Name { get; } | public string Name { get; } | ||||
public string Summary { get; } | public string Summary { get; } | ||||
@@ -17,38 +18,39 @@ namespace Discord.Commands | |||||
public IReadOnlyList<PreconditionAttribute> Preconditions { get; } | public IReadOnlyList<PreconditionAttribute> Preconditions { get; } | ||||
internal Module(CommandService service, object instance, ModuleAttribute moduleAttr, TypeInfo typeInfo) | |||||
internal Module(TypeInfo source, CommandService service, object instance, ModuleAttribute moduleAttr) | |||||
{ | { | ||||
Source = source; | |||||
Service = service; | Service = service; | ||||
Name = typeInfo.Name; | |||||
Name = source.Name; | |||||
Instance = instance; | Instance = instance; | ||||
var summaryAttr = typeInfo.GetCustomAttribute<SummaryAttribute>(); | |||||
var summaryAttr = source.GetCustomAttribute<SummaryAttribute>(); | |||||
if (summaryAttr != null) | if (summaryAttr != null) | ||||
Summary = summaryAttr.Text; | Summary = summaryAttr.Text; | ||||
var descriptionAttr = typeInfo.GetCustomAttribute<DescriptionAttribute>(); | |||||
var descriptionAttr = source.GetCustomAttribute<DescriptionAttribute>(); | |||||
if (descriptionAttr != null) | if (descriptionAttr != null) | ||||
Description = descriptionAttr.Text; | Description = descriptionAttr.Text; | ||||
List<Command> commands = new List<Command>(); | List<Command> commands = new List<Command>(); | ||||
SearchClass(instance, commands, typeInfo, moduleAttr.Prefix ?? ""); | |||||
SearchClass(source, instance, commands, moduleAttr.Prefix ?? ""); | |||||
Commands = commands; | Commands = commands; | ||||
Preconditions = BuildPreconditions(typeInfo); | |||||
Preconditions = BuildPreconditions(); | |||||
} | } | ||||
private void SearchClass(object instance, List<Command> commands, TypeInfo typeInfo, string groupPrefix) | |||||
private void SearchClass(TypeInfo parentType, object instance, List<Command> commands, string groupPrefix) | |||||
{ | { | ||||
if (groupPrefix != "") | if (groupPrefix != "") | ||||
groupPrefix += " "; | groupPrefix += " "; | ||||
foreach (var method in typeInfo.DeclaredMethods) | |||||
foreach (var method in parentType.DeclaredMethods) | |||||
{ | { | ||||
var cmdAttr = method.GetCustomAttribute<CommandAttribute>(); | var cmdAttr = method.GetCustomAttribute<CommandAttribute>(); | ||||
if (cmdAttr != null) | if (cmdAttr != null) | ||||
commands.Add(new Command(this, instance, cmdAttr, method, groupPrefix)); | |||||
commands.Add(new Command(method, this, instance, cmdAttr, groupPrefix)); | |||||
} | } | ||||
foreach (var type in typeInfo.DeclaredNestedTypes) | |||||
foreach (var type in parentType.DeclaredNestedTypes) | |||||
{ | { | ||||
var groupAttrib = type.GetCustomAttribute<GroupAttribute>(); | var groupAttrib = type.GetCustomAttribute<GroupAttribute>(); | ||||
if (groupAttrib != null) | if (groupAttrib != null) | ||||
@@ -58,14 +60,14 @@ namespace Discord.Commands | |||||
nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; | nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; | ||||
else | else | ||||
nextGroupPrefix = groupPrefix; | nextGroupPrefix = groupPrefix; | ||||
SearchClass(ReflectionUtils.CreateObject(type, Service), commands, type, nextGroupPrefix); | |||||
SearchClass(type, ReflectionUtils.CreateObject(type, Service), commands, nextGroupPrefix); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
private IReadOnlyList<PreconditionAttribute> BuildPreconditions(TypeInfo typeInfo) | |||||
private IReadOnlyList<PreconditionAttribute> BuildPreconditions() | |||||
{ | { | ||||
return typeInfo.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray(); | |||||
return Source.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray(); | |||||
} | } | ||||
public override string ToString() => Name; | public override string ToString() => Name; | ||||