Browse Source

SearchAsync now returns a tuple, where Item1 is a list of confirmed types without dependencies.

Item2 is a dictionary of key - subtype outside of parent class, value - parent module.

Added ConfirmTypeInfoAsync, because I had to confirm group parent type is valid too.

Added new argument Dictionary<Type, ModuleInfo> moduleDefs to methods:
BuildModule, BuildSubTypes, BuildAsync.

Modules with parent dependencies expect this argument to have value.
pull/1399/head
LtLi0n 5 years ago
parent
commit
c170fbd21e
1 changed files with 64 additions and 22 deletions
  1. +64
    -22
      src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs

+ 64
- 22
src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs View File

@@ -12,38 +12,73 @@ namespace Discord.Commands
{ {
private static readonly TypeInfo ModuleTypeInfo = typeof(IModuleBase).GetTypeInfo(); private static readonly TypeInfo ModuleTypeInfo = typeof(IModuleBase).GetTypeInfo();


public static async Task<IReadOnlyList<TypeInfo>> SearchAsync(Assembly assembly, CommandService service)
///<summary>Value1 - ready types, Value2 - types dependant on Value1.</summary>
/// <param name="assembly"></param>
/// <param name="service"></param>
/// <returns></returns>
public static async Task<Tuple<IReadOnlyList<TypeInfo>, IReadOnlyDictionary<TypeInfo, TypeInfo>>> SearchAsync(Assembly assembly, CommandService service)
{ {
bool IsLoadableModule(TypeInfo info)
{
return info.DeclaredMethods.Any(x => x.GetCustomAttribute<CommandAttribute>() != null) &&
info.GetCustomAttribute<DontAutoLoadAttribute>() == null;
}

var result = new List<TypeInfo>();
var standardModules = new List<TypeInfo>();
var queuedModules = new Dictionary<TypeInfo, TypeInfo>();


foreach (var typeInfo in assembly.DefinedTypes) foreach (var typeInfo in assembly.DefinedTypes)
{ {
if (typeInfo.IsPublic || typeInfo.IsNestedPublic)
//SubTypes outside of parent class. Require
var groupAttr = typeInfo.GetCustomAttribute<GroupAttribute>();
if (groupAttr != null)
{ {
if (IsValidModuleDefinition(typeInfo) &&
!typeInfo.IsDefined(typeof(DontAutoLoadAttribute)))
if (groupAttr.ParentModule != null)
{ {
result.Add(typeInfo);
var parentTypeInfo = groupAttr.ParentModule.GetTypeInfo();
bool subTypeIsValid = await ConfirmTypeInfoAsync(service, parentTypeInfo);
if(subTypeIsValid)
{
queuedModules.Add(typeInfo, parentTypeInfo);
}
continue;
} }
} }
else if (IsLoadableModule(typeInfo))

bool typeInfoIsValid = await ConfirmTypeInfoAsync(service, typeInfo);
if(typeInfoIsValid)
{ {
await service._cmdLogger.WarningAsync($"Class {typeInfo.FullName} is not public and cannot be loaded. To suppress this message, mark the class with {nameof(DontAutoLoadAttribute)}.").ConfigureAwait(false);
standardModules.Add(typeInfo);
} }
} }


return result;
return Tuple.Create<IReadOnlyList<TypeInfo>, IReadOnlyDictionary<TypeInfo, TypeInfo>>(standardModules, queuedModules);
}


private static bool IsLoadableModule(TypeInfo info)
{
return info.DeclaredMethods.Any(
x => x.GetCustomAttribute<CommandAttribute>() != null) &&
info.GetCustomAttribute<DontAutoLoadAttribute>() == null;
}

///<summary>Confirm if type is valid. If so, add it to the specified modules list.</summary>
private static async Task<bool> ConfirmTypeInfoAsync(CommandService service, TypeInfo typeInfo)
{
if (typeInfo.IsPublic || typeInfo.IsNestedPublic)
{
if (IsValidModuleDefinition(typeInfo) &&
!typeInfo.IsDefined(typeof(DontAutoLoadAttribute)))
{
return true;
}
}
else if (IsLoadableModule(typeInfo))
{
await service._cmdLogger.WarningAsync($"Class {typeInfo.FullName} is not public and cannot be loaded. To suppress this message, mark the class with {nameof(DontAutoLoadAttribute)}.").ConfigureAwait(false);
}

return false;
} }




public static Task<Dictionary<Type, ModuleInfo>> BuildAsync(CommandService service, IServiceProvider services, params TypeInfo[] validTypes) => BuildAsync(validTypes, service, services); public static Task<Dictionary<Type, ModuleInfo>> BuildAsync(CommandService service, IServiceProvider services, params TypeInfo[] validTypes) => BuildAsync(validTypes, service, services);
public static async Task<Dictionary<Type, ModuleInfo>> BuildAsync(IEnumerable<TypeInfo> validTypes, CommandService service, IServiceProvider services)
public static async Task<Dictionary<Type, ModuleInfo>> BuildAsync(IEnumerable<TypeInfo> validTypes, CommandService service, IServiceProvider services, Dictionary<Type, ModuleInfo> moduleDefs = null)
{ {
/*if (!validTypes.Any()) /*if (!validTypes.Any())
throw new InvalidOperationException("Could not find any valid modules from the given selection");*/ throw new InvalidOperationException("Could not find any valid modules from the given selection");*/
@@ -62,8 +97,8 @@ namespace Discord.Commands


var module = new ModuleBuilder(service, null); var module = new ModuleBuilder(service, null);


BuildModule(module, typeInfo, service, services);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services);
BuildModule(module, typeInfo, service, services, moduleDefs);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services, moduleDefs);
builtTypes.Add(typeInfo); builtTypes.Add(typeInfo);


result[typeInfo.AsType()] = module.Build(service, services); result[typeInfo.AsType()] = module.Build(service, services);
@@ -74,7 +109,7 @@ namespace Discord.Commands
return result; return result;
} }


private static void BuildSubTypes(ModuleBuilder builder, IEnumerable<TypeInfo> subTypes, List<TypeInfo> builtTypes, CommandService service, IServiceProvider services)
private static void BuildSubTypes(ModuleBuilder builder, IEnumerable<TypeInfo> subTypes, List<TypeInfo> builtTypes, CommandService service, IServiceProvider services, Dictionary<Type, ModuleInfo> moduleDefs)
{ {
foreach (var typeInfo in subTypes) foreach (var typeInfo in subTypes)
{ {
@@ -86,15 +121,15 @@ namespace Discord.Commands
builder.AddModule((module) => builder.AddModule((module) =>
{ {
BuildModule(module, typeInfo, service, services);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services);
BuildModule(module, typeInfo, service, services, moduleDefs);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services, moduleDefs);
}); });


builtTypes.Add(typeInfo); builtTypes.Add(typeInfo);
} }
} }


private static void BuildModule(ModuleBuilder builder, TypeInfo typeInfo, CommandService service, IServiceProvider services)
private static void BuildModule(ModuleBuilder builder, TypeInfo typeInfo, CommandService service, IServiceProvider services, Dictionary<Type, ModuleInfo> moduleDefs)
{ {
var attributes = typeInfo.GetCustomAttributes(); var attributes = typeInfo.GetCustomAttributes();
builder.TypeInfo = typeInfo; builder.TypeInfo = typeInfo;
@@ -118,6 +153,13 @@ namespace Discord.Commands
case GroupAttribute group: case GroupAttribute group:
builder.Name = builder.Name ?? group.Prefix; builder.Name = builder.Name ?? group.Prefix;
builder.Group = group.Prefix; builder.Group = group.Prefix;
if(group.ParentModule != null)
{
foreach (string parentAlias in moduleDefs[group.ParentModule].Aliases)
{
builder.AddAliases(parentAlias);
}
}
builder.AddAliases(group.Prefix); builder.AddAliases(group.Prefix);
break; break;
case PreconditionAttribute precondition: case PreconditionAttribute precondition:


Loading…
Cancel
Save