Add callback method for when a module class has been added (#934)

commit 5b047bf02b4299f34172cac05dc7e4a84ecc108c
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Fri Feb 2 22:22:00 2018 +0100

    [feature/OnModuleAdded] Quickstart fixes (#946)

    * Quickstart: fix minor derp

    * Other overdue fixes

commit bd3e9eee943b9092cc45217b19ff95bae359f888
Author: Christopher F <computerizedtaco@gmail.com>
Date:   Sat Jan 27 16:51:18 2018 -0500

    Resort usings in ModuleBase

commit 8042767579b337fdae7fe48e0a6ea2f007aef440
Author: Christopher F <computerizedtaco@gmail.com>
Date:   Sat Jan 27 16:41:39 2018 -0500

    Clean up removed owned IServiceProvider

commit 30066cb102ffbd65906ead72a377811aa501abba
Author: Christopher F <computerizedtaco@gmail.com>
Date:   Sat Jan 27 16:37:22 2018 -0500

    Remove redundant try-catch around OnModuleBuilding invocation

    If this exception is going to be rethrown, there's no reason to include
    a try-catch.

commit 60c7c31d4476c498a97ae0536ec5792f08efb89b
Author: Christopher F <computerizedtaco@gmail.com>
Date:   Sat Jan 27 16:36:27 2018 -0500

    Include the ModuleBuilder in OnModuleBuilding

    This allows modules hooking into OnModuleBuilding method to mutate
    theirselves at runtime.

commit b6a9ff57860ff3bddbad7ca850fd331529cb8e6e
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 22 13:17:14 2018 +0100

    #DERP

commit f623d19c68c5642a44898a561f77ed82d53fd103
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 22 13:15:31 2018 +0100

    Resolution for #937 because it's literally 4 lines of code

commit 8272c9675b0d63b4100aaf57f5067d635b68f5e6
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 22 11:39:28 2018 +0100

    Re-adjust quickstart

commit e30b9071351b69baa30a93a4851516dca9ea43cf
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 22 11:35:08 2018 +0100

    Undo experimental changes, request IServiceProvider instance everywhere instead

commit ad7e0a46c8709e845dfacdc298a893e22dc11567
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Fri Jan 19 03:40:27 2018 +0100

    Fix quickstart leftover from previous draft

commit e3349ef3d400bb3ad8cb28dd4234d5316a80bcc4
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Fri Jan 19 03:33:46 2018 +0100

    Doc comment on items

commit 81bd9111faaf98a52679daae863ab04dce96e63e
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Fri Jan 19 03:16:44 2018 +0100

    Add comment about the ServiceProviderFactory in the quickstart

commit 72b5e6c8a149d8e989b46351965daa14f8ca318c
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Fri Jan 19 03:10:40 2018 +0100

    Remove superfluous comments, provide simpler alternative for setting the ServiceProvider.

commit 74b17b0e04e2c413397a2e1b66ff814615326205
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Tue Jan 16 18:06:28 2018 +0100

    Experimental change for feedback

commit 7b100e99bb119be190006d1cd8e403776930e401
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 15 23:34:06 2018 +0100

    * Make the service provider parameters required

    * Adjust quickstart guide to reflect changes

commit 7f1b792946ac6b950922b06178aa5cc37d9f4144
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 15 20:04:37 2018 +0100

    I..... missed one.

commit 031b289d80604666dde62619e521af303203d48d
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 15 20:02:20 2018 +0100

    Rename method to more intuitive 'OnModuleBuilding'

commit 9a166ef1d0baecd21e4e5b965e2ac364feddbe2e
Author: Joe4evr <jii.geugten@gmail.com>
Date:   Mon Jan 15 19:09:10 2018 +0100

    Add callback method for when a module class has been added to the CommandService.
This commit is contained in:
Christopher F
2018-02-18 19:15:52 -05:00
parent 178ea8de4d
commit bb8ebc13d2
8 changed files with 196 additions and 136 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
@@ -18,6 +19,7 @@ namespace Discord.Commands.Builders
public string Name { get; set; }
public string Summary { get; set; }
public string Remarks { get; set; }
public string Group { get; set; }
public IReadOnlyList<CommandBuilder> Commands => _commands;
public IReadOnlyList<ModuleBuilder> Modules => _submodules;
@@ -25,6 +27,8 @@ namespace Discord.Commands.Builders
public IReadOnlyList<Attribute> Attributes => _attributes;
public IReadOnlyList<string> Aliases => _aliases;
internal TypeInfo TypeInfo { get; set; }
//Automatic
internal ModuleBuilder(CommandService service, ModuleBuilder parent)
{
@@ -111,17 +115,23 @@ namespace Discord.Commands.Builders
return this;
}
private ModuleInfo BuildImpl(CommandService service, ModuleInfo parent = null)
private ModuleInfo BuildImpl(CommandService service, IServiceProvider services, ModuleInfo parent = null)
{
//Default name to first alias
if (Name == null)
Name = _aliases[0];
return new ModuleInfo(this, service, parent);
if (TypeInfo != null)
{
var moduleInstance = ReflectionUtils.CreateObject<IModuleBase>(TypeInfo, service, services);
moduleInstance.OnModuleBuilding(service, this);
}
return new ModuleInfo(this, service, services, parent);
}
public ModuleInfo Build(CommandService service) => BuildImpl(service);
public ModuleInfo Build(CommandService service, IServiceProvider services) => BuildImpl(service, services);
internal ModuleInfo Build(CommandService service, ModuleInfo parent) => BuildImpl(service, parent);
internal ModuleInfo Build(CommandService service, IServiceProvider services, ModuleInfo parent) => BuildImpl(service, services, parent);
}
}

View File

@@ -42,8 +42,8 @@ namespace Discord.Commands
}
public static Task<Dictionary<Type, ModuleInfo>> BuildAsync(CommandService service, params TypeInfo[] validTypes) => BuildAsync(validTypes, service);
public static async Task<Dictionary<Type, ModuleInfo>> BuildAsync(IEnumerable<TypeInfo> validTypes, CommandService service)
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)
{
/*if (!validTypes.Any())
throw new InvalidOperationException("Could not find any valid modules from the given selection");*/
@@ -63,11 +63,11 @@ namespace Discord.Commands
var module = new ModuleBuilder(service, null);
BuildModule(module, typeInfo, service);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service);
BuildModule(module, typeInfo, service, services);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services);
builtTypes.Add(typeInfo);
result[typeInfo.AsType()] = module.Build(service);
result[typeInfo.AsType()] = module.Build(service, services);
}
await service._cmdLogger.DebugAsync($"Successfully built {builtTypes.Count} modules.").ConfigureAwait(false);
@@ -75,7 +75,7 @@ namespace Discord.Commands
return result;
}
private static void BuildSubTypes(ModuleBuilder builder, IEnumerable<TypeInfo> subTypes, List<TypeInfo> builtTypes, CommandService service)
private static void BuildSubTypes(ModuleBuilder builder, IEnumerable<TypeInfo> subTypes, List<TypeInfo> builtTypes, CommandService service, IServiceProvider services)
{
foreach (var typeInfo in subTypes)
{
@@ -87,17 +87,18 @@ namespace Discord.Commands
builder.AddModule((module) =>
{
BuildModule(module, typeInfo, service);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service);
BuildModule(module, typeInfo, service, services);
BuildSubTypes(module, typeInfo.DeclaredNestedTypes, builtTypes, service, services);
});
builtTypes.Add(typeInfo);
}
}
private static void BuildModule(ModuleBuilder builder, TypeInfo typeInfo, CommandService service)
private static void BuildModule(ModuleBuilder builder, TypeInfo typeInfo, CommandService service, IServiceProvider services)
{
var attributes = typeInfo.GetCustomAttributes();
builder.TypeInfo = typeInfo;
foreach (var attribute in attributes)
{
@@ -117,6 +118,7 @@ namespace Discord.Commands
break;
case GroupAttribute group:
builder.Name = builder.Name ?? group.Prefix;
builder.Group = group.Prefix;
builder.AddAliases(group.Prefix);
break;
case PreconditionAttribute precondition:
@@ -140,12 +142,12 @@ namespace Discord.Commands
{
builder.AddCommand((command) =>
{
BuildCommand(command, typeInfo, method, service);
BuildCommand(command, typeInfo, method, service, services);
});
}
}
private static void BuildCommand(CommandBuilder builder, TypeInfo typeInfo, MethodInfo method, CommandService service)
private static void BuildCommand(CommandBuilder builder, TypeInfo typeInfo, MethodInfo method, CommandService service, IServiceProvider serviceprovider)
{
var attributes = method.GetCustomAttributes();
@@ -191,7 +193,7 @@ namespace Discord.Commands
{
builder.AddParameter((parameter) =>
{
BuildParameter(parameter, paramInfo, pos++, count, service);
BuildParameter(parameter, paramInfo, pos++, count, service, serviceprovider);
});
}
@@ -227,7 +229,7 @@ namespace Discord.Commands
builder.Callback = ExecuteCallback;
}
private static void BuildParameter(ParameterBuilder builder, System.Reflection.ParameterInfo paramInfo, int position, int count, CommandService service)
private static void BuildParameter(ParameterBuilder builder, System.Reflection.ParameterInfo paramInfo, int position, int count, CommandService service, IServiceProvider services)
{
var attributes = paramInfo.GetCustomAttributes();
var paramType = paramInfo.ParameterType;
@@ -245,7 +247,7 @@ namespace Discord.Commands
builder.Summary = summary.Text;
break;
case OverrideTypeReaderAttribute typeReader:
builder.TypeReader = GetTypeReader(service, paramType, typeReader.TypeReader);
builder.TypeReader = GetTypeReader(service, paramType, typeReader.TypeReader, services);
break;
case ParamArrayAttribute _:
builder.IsMultiple = true;
@@ -285,7 +287,7 @@ namespace Discord.Commands
}
}
private static TypeReader GetTypeReader(CommandService service, Type paramType, Type typeReaderType)
private static TypeReader GetTypeReader(CommandService service, Type paramType, Type typeReaderType, IServiceProvider services)
{
var readers = service.GetTypeReaders(paramType);
TypeReader reader = null;
@@ -296,7 +298,7 @@ namespace Discord.Commands
}
//We dont have a cached type reader, create one
reader = ReflectionUtils.CreateObject<TypeReader>(typeReaderType.GetTypeInfo(), service, EmptyServiceProvider.Instance);
reader = ReflectionUtils.CreateObject<TypeReader>(typeReaderType.GetTypeInfo(), service, services);
service.AddTypeReader(paramType, reader);
return reader;

View File

@@ -1,5 +1,3 @@
using Discord.Commands.Builders;
using Discord.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -8,6 +6,9 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Discord.Commands.Builders;
using Discord.Logging;
namespace Discord.Commands
{
@@ -85,7 +86,8 @@ namespace Discord.Commands
var builder = new ModuleBuilder(this, null, primaryAlias);
buildFunc(builder);
var module = builder.Build(this);
var module = builder.Build(this, null);
return LoadModuleInternal(module);
}
finally
@@ -93,8 +95,8 @@ namespace Discord.Commands
_moduleLock.Release();
}
}
public Task<ModuleInfo> AddModuleAsync<T>() => AddModuleAsync(typeof(T));
public async Task<ModuleInfo> AddModuleAsync(Type type)
public Task<ModuleInfo> AddModuleAsync<T>(IServiceProvider services) => AddModuleAsync(typeof(T), services);
public async Task<ModuleInfo> AddModuleAsync(Type type, IServiceProvider services)
{
await _moduleLock.WaitAsync().ConfigureAwait(false);
try
@@ -104,7 +106,7 @@ namespace Discord.Commands
if (_typedModuleDefs.ContainsKey(type))
throw new ArgumentException($"This module has already been added.");
var module = (await ModuleClassBuilder.BuildAsync(this, typeInfo).ConfigureAwait(false)).FirstOrDefault();
var module = (await ModuleClassBuilder.BuildAsync(this, services, typeInfo).ConfigureAwait(false)).FirstOrDefault();
if (module.Value == default(ModuleInfo))
throw new InvalidOperationException($"Could not build the module {type.FullName}, did you pass an invalid type?");
@@ -118,13 +120,13 @@ namespace Discord.Commands
_moduleLock.Release();
}
}
public async Task<IEnumerable<ModuleInfo>> AddModulesAsync(Assembly assembly)
public async Task<IEnumerable<ModuleInfo>> AddModulesAsync(Assembly assembly, IServiceProvider services)
{
await _moduleLock.WaitAsync().ConfigureAwait(false);
try
{
var types = await ModuleClassBuilder.SearchAsync(assembly, this).ConfigureAwait(false);
var moduleDefs = await ModuleClassBuilder.BuildAsync(types, this).ConfigureAwait(false);
var moduleDefs = await ModuleClassBuilder.BuildAsync(types, this, services).ConfigureAwait(false);
foreach (var info in moduleDefs)
{
@@ -224,7 +226,7 @@ namespace Discord.Commands
var readers = _typeReaders.GetOrAdd(typeof(Nullable<>).MakeGenericType(valueType), x => new ConcurrentDictionary<Type, TypeReader>());
var nullableReader = NullableTypeReader.Create(valueType, valueTypeReader);
readers[nullableReader.GetType()] = nullableReader;
}
}
internal IDictionary<Type, TypeReader> GetTypeReaders(Type type)
{
if (_typeReaders.TryGetValue(type, out var definedTypeReaders))
@@ -277,92 +279,94 @@ namespace Discord.Commands
public async Task<IResult> ExecuteAsync(ICommandContext context, string input, IServiceProvider services = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
services = services ?? EmptyServiceProvider.Instance;
var searchResult = Search(context, input);
if (!searchResult.IsSuccess)
return searchResult;
var commands = searchResult.Commands;
var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>();
foreach (var match in commands)
using (var scope = services.CreateScope())
{
preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, services).ConfigureAwait(false);
}
var searchResult = Search(context, input);
if (!searchResult.IsSuccess)
return searchResult;
var successfulPreconditions = preconditionResults
.Where(x => x.Value.IsSuccess)
.ToArray();
var commands = searchResult.Commands;
var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>();
if (successfulPreconditions.Length == 0)
{
//All preconditions failed, return the one from the highest priority command
var bestCandidate = preconditionResults
.OrderByDescending(x => x.Key.Command.Priority)
.FirstOrDefault(x => !x.Value.IsSuccess);
return bestCandidate.Value;
}
//If we get this far, at least one precondition was successful.
var parseResultsDict = new Dictionary<CommandMatch, ParseResult>();
foreach (var pair in successfulPreconditions)
{
var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, services).ConfigureAwait(false);
if (parseResult.Error == CommandError.MultipleMatches)
foreach (var match in commands)
{
IReadOnlyList<TypeReaderValue> argList, paramList;
switch (multiMatchHandling)
preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, scope.ServiceProvider).ConfigureAwait(false);
}
var successfulPreconditions = preconditionResults
.Where(x => x.Value.IsSuccess)
.ToArray();
if (successfulPreconditions.Length == 0)
{
//All preconditions failed, return the one from the highest priority command
var bestCandidate = preconditionResults
.OrderByDescending(x => x.Key.Command.Priority)
.FirstOrDefault(x => !x.Value.IsSuccess);
return bestCandidate.Value;
}
//If we get this far, at least one precondition was successful.
var parseResultsDict = new Dictionary<CommandMatch, ParseResult>();
foreach (var pair in successfulPreconditions)
{
var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, scope.ServiceProvider).ConfigureAwait(false);
if (parseResult.Error == CommandError.MultipleMatches)
{
case MultiMatchHandling.Best:
argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
parseResult = ParseResult.FromSuccess(argList, paramList);
break;
IReadOnlyList<TypeReaderValue> argList, paramList;
switch (multiMatchHandling)
{
case MultiMatchHandling.Best:
argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
parseResult = ParseResult.FromSuccess(argList, paramList);
break;
}
}
parseResultsDict[pair.Key] = parseResult;
}
parseResultsDict[pair.Key] = parseResult;
}
// Calculates the 'score' of a command given a parse result
float CalculateScore(CommandMatch match, ParseResult parseResult)
{
float argValuesScore = 0, paramValuesScore = 0;
if (match.Command.Parameters.Count > 0)
// Calculates the 'score' of a command given a parse result
float CalculateScore(CommandMatch match, ParseResult parseResult)
{
var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
float argValuesScore = 0, paramValuesScore = 0;
argValuesScore = argValuesSum / match.Command.Parameters.Count;
paramValuesScore = paramValuesSum / match.Command.Parameters.Count;
if (match.Command.Parameters.Count > 0)
{
var argValuesSum = parseResult.ArgValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
var paramValuesSum = parseResult.ParamValues?.Sum(x => x.Values.OrderByDescending(y => y.Score).FirstOrDefault().Score) ?? 0;
argValuesScore = argValuesSum / match.Command.Parameters.Count;
paramValuesScore = paramValuesSum / match.Command.Parameters.Count;
}
var totalArgsScore = (argValuesScore + paramValuesScore) / 2;
return match.Command.Priority + totalArgsScore * 0.99f;
}
var totalArgsScore = (argValuesScore + paramValuesScore) / 2;
return match.Command.Priority + totalArgsScore * 0.99f;
//Order the parse results by their score so that we choose the most likely result to execute
var parseResults = parseResultsDict
.OrderByDescending(x => CalculateScore(x.Key, x.Value));
var successfulParses = parseResults
.Where(x => x.Value.IsSuccess)
.ToArray();
if (successfulParses.Length == 0)
{
//All parses failed, return the one from the highest priority command, using score as a tie breaker
var bestMatch = parseResults
.FirstOrDefault(x => !x.Value.IsSuccess);
return bestMatch.Value;
}
//If we get this far, at least one parse was successful. Execute the most likely overload.
var chosenOverload = successfulParses[0];
return await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, scope.ServiceProvider).ConfigureAwait(false);
}
//Order the parse results by their score so that we choose the most likely result to execute
var parseResults = parseResultsDict
.OrderByDescending(x => CalculateScore(x.Key, x.Value));
var successfulParses = parseResults
.Where(x => x.Value.IsSuccess)
.ToArray();
if (successfulParses.Length == 0)
{
//All parses failed, return the one from the highest priority command, using score as a tie breaker
var bestMatch = parseResults
.FirstOrDefault(x => !x.Value.IsSuccess);
return bestMatch.Value;
}
//If we get this far, at least one parse was successful. Execute the most likely overload.
var chosenOverload = successfulParses[0];
return await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false);
}
}
}

View File

@@ -1,4 +1,6 @@
namespace Discord.Commands
using System;
namespace Discord.Commands
{
public class CommandServiceConfig
{
@@ -18,5 +20,11 @@
/// <summary> Determines whether extra parameters should be ignored. </summary>
public bool IgnoreExtraArgs { get; set; } = false;
///// <summary> Gets or sets the <see cref="IServiceProvider"/> to use. </summary>
//public IServiceProvider ServiceProvider { get; set; } = null;
///// <summary> Gets or sets a factory function for the <see cref="IServiceProvider"/> to use. </summary>
//public Func<CommandService, IServiceProvider> ServiceProviderFactory { get; set; } = null;
}
}

View File

@@ -1,4 +1,6 @@
namespace Discord.Commands
using Discord.Commands.Builders;
namespace Discord.Commands
{
internal interface IModuleBase
{
@@ -7,5 +9,7 @@
void BeforeExecute(CommandInfo command);
void AfterExecute(CommandInfo command);
void OnModuleBuilding(CommandService commandService, ModuleBuilder builder);
}
}

View File

@@ -2,7 +2,7 @@ using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using Discord.Commands.Builders;
namespace Discord.Commands
@@ -13,6 +13,7 @@ namespace Discord.Commands
public string Name { get; }
public string Summary { get; }
public string Remarks { get; }
public string Group { get; }
public IReadOnlyList<string> Aliases { get; }
public IReadOnlyList<CommandInfo> Commands { get; }
@@ -22,21 +23,26 @@ namespace Discord.Commands
public ModuleInfo Parent { get; }
public bool IsSubmodule => Parent != null;
internal ModuleInfo(ModuleBuilder builder, CommandService service, ModuleInfo parent = null)
//public TypeInfo TypeInfo { get; }
internal ModuleInfo(ModuleBuilder builder, CommandService service, IServiceProvider services, ModuleInfo parent = null)
{
Service = service;
Name = builder.Name;
Summary = builder.Summary;
Remarks = builder.Remarks;
Group = builder.Group;
Parent = parent;
//TypeInfo = builder.TypeInfo;
Aliases = BuildAliases(builder, service).ToImmutableArray();
Commands = builder.Commands.Select(x => x.Build(this, service)).ToImmutableArray();
Preconditions = BuildPreconditions(builder).ToImmutableArray();
Attributes = BuildAttributes(builder).ToImmutableArray();
Submodules = BuildSubmodules(builder, service).ToImmutableArray();
Submodules = BuildSubmodules(builder, service, services).ToImmutableArray();
}
private static IEnumerable<string> BuildAliases(ModuleBuilder builder, CommandService service)
@@ -66,12 +72,12 @@ namespace Discord.Commands
return result;
}
private List<ModuleInfo> BuildSubmodules(ModuleBuilder parent, CommandService service)
private List<ModuleInfo> BuildSubmodules(ModuleBuilder parent, CommandService service, IServiceProvider services)
{
var result = new List<ModuleInfo>();
foreach (var submodule in parent.Modules)
result.Add(submodule.Build(service, this));
result.Add(submodule.Build(service, services, this));
return result;
}

View File

@@ -1,5 +1,6 @@
using System;
using System;
using System.Threading.Tasks;
using Discord.Commands.Builders;
namespace Discord.Commands
{
@@ -23,15 +24,18 @@ namespace Discord.Commands
{
}
protected virtual void OnModuleBuilding(CommandService commandService, ModuleBuilder builder)
{
}
//IModuleBase
void IModuleBase.SetContext(ICommandContext context)
{
var newValue = context as T;
Context = newValue ?? throw new InvalidOperationException($"Invalid context type. Expected {typeof(T).Name}, got {context.GetType().Name}");
}
void IModuleBase.BeforeExecute(CommandInfo command) => BeforeExecute(command);
void IModuleBase.AfterExecute(CommandInfo command) => AfterExecute(command);
void IModuleBase.OnModuleBuilding(CommandService commandService, ModuleBuilder builder) => OnModuleBuilding(commandService, builder);
}
}