Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Color-Chan.Discord.sln
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ButtonArgs", "samples\Butto
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentsV2", "samples\ComponentsV2\ComponentsV2.csproj", "{3D545B51-0245-43BF-9588-2C299B7DD9A5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Color-Chan.Discord.Commands.Tests.Valid2", "tests\mockCommandAssemblies\Color-Chan.Discord.Commands.Tests.Valid2\Color-Chan.Discord.Commands.Tests.Valid2.csproj", "{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -136,6 +138,10 @@ Global
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Release|Any CPU.Build.0 = Release|Any CPU
{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -162,6 +168,7 @@ Global
{4D344610-2AD1-44D1-A3FE-76908972AA9B} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
{7F0D86B2-209D-4C6A-BB68-489C59756FC2} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
{3D545B51-0245-43BF-9588-2C299B7DD9A5} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
{A19857F5-7AC6-4CAE-BAB4-7CE371F96300} = {ADBC5773-D0F4-4A9E-BC6F-6EF9220718A4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AC84D902-ABC1-47C3-9993-F769F483E5CE}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ namespace Color_Chan.Discord.Commands.Services.Builders;
public interface ISlashCommandBuildService
{
/// <summary>
/// Builds all commands in a specific <paramref name="assembly" /> and stores them in a
/// Builds all commands in specific <paramref name="assemblies" /> and stores them in a
/// <see cref="IReadOnlyList{T}" /> of <see cref="KeyValuePair{T,U}" /> of <see cref="string" />,
/// <see cref="ISlashCommandInfo" />.
/// </summary>
/// <param name="assembly">
/// The <see cref="Assembly" /> where the <see cref="ISlashCommandBuildService" /> will search for commands.
/// <param name="assemblies">
/// The <see cref="Assembly" />s where the <see cref="ISlashCommandBuildService" /> will search for commands.
/// </param>
Comment thread
BrammyS marked this conversation as resolved.
/// <returns>
/// A <see cref="IReadOnlyList{T}" /> of <see cref="KeyValuePair{T,U}" /> of <see cref="string" />,
/// <see cref="ISlashCommandInfo" />.
/// The key <see cref="string" /> contains the command name.
/// And the value <see cref="ISlashCommandInfo" /> contains the commands information to execute it.
/// </returns>
IReadOnlyList<KeyValuePair<string, ISlashCommandInfo>> BuildSlashCommandInfos(Assembly assembly);
IReadOnlyList<KeyValuePair<string, ISlashCommandInfo>> BuildSlashCommandInfos(params Assembly[] assemblies);
Comment thread
BrammyS marked this conversation as resolved.

/// <summary>
/// Get all the interaction command modules.
Expand Down
40 changes: 28 additions & 12 deletions src/Color-Chan.Discord.Commands/Services/ISlashCommandService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ namespace Color_Chan.Discord.Commands.Services;
public interface ISlashCommandService
{
/// <summary>
/// Add all interaction commands in an <see cref="Assembly" /> to the <see cref="ISlashCommandService" />.
/// Add all interaction commands in <see cref="Assembly" />s to the <see cref="ISlashCommandService" />.
/// </summary>
/// <param name="assembly">The <see cref="Assembly" /> where the commands are located.</param>
/// <param name="assemblies">The <see cref="Assembly" />s where the commands are located.</param>
/// <seealso cref="Result" />
/// <seealso cref="SlashCommandAttribute" />
Task AddInteractionCommandsAsync(Assembly assembly);
Task AddInteractionCommandsAsync(params Assembly[] assemblies);
Comment thread
BrammyS marked this conversation as resolved.
Comment thread
BrammyS marked this conversation as resolved.

/// <summary>
/// Execute a specific command with their dependencies.
Expand All @@ -41,9 +41,14 @@ public interface ISlashCommandService
/// </returns>
/// <seealso cref="Result" />
/// <seealso cref="SlashCommandAttribute" />
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(MethodInfo commandMethod, IEnumerable<ISlashCommandOptionInfo>? options,
IEnumerable<InteractionRequirementAttribute>? requirements, ISlashCommandContext context,
List<IDiscordInteractionOption>? suppliedOptions = null, IServiceProvider? serviceProvider = null);
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(
MethodInfo commandMethod,
IEnumerable<ISlashCommandOptionInfo>? options,
IEnumerable<InteractionRequirementAttribute>? requirements,
ISlashCommandContext context,
List<IDiscordInteractionOption>? suppliedOptions = null,
IServiceProvider? serviceProvider = null
);

/// <summary>
/// Execute a specific command with their dependencies.
Expand All @@ -61,8 +66,12 @@ Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(MethodInfo co
/// </returns>
/// <seealso cref="Result" />
/// <seealso cref="SlashCommandAttribute" />
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(ISlashCommandInfo commandInfo, ISlashCommandContext context, List<IDiscordInteractionOption>? suppliedOptions = null,
IServiceProvider? serviceProvider = null);
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(
ISlashCommandInfo commandInfo,
ISlashCommandContext context,
List<IDiscordInteractionOption>? suppliedOptions = null,
IServiceProvider? serviceProvider = null
);

/// <summary>
/// Execute a specific command with their dependencies.
Expand All @@ -80,8 +89,12 @@ Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(ISlashCommand
/// </returns>
/// <seealso cref="Result" />
/// <seealso cref="SlashCommandAttribute" />
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(ISlashCommandOptionInfo commandOptionInfo, ISlashCommandContext context,
List<IDiscordInteractionOption>? suppliedOptions = null, IServiceProvider? serviceProvider = null);
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(
ISlashCommandOptionInfo commandOptionInfo,
ISlashCommandContext context,
List<IDiscordInteractionOption>? suppliedOptions = null,
IServiceProvider? serviceProvider = null
);

/// <summary>
/// Execute a specific command with their dependencies.
Expand All @@ -98,8 +111,11 @@ Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(ISlashCommand
/// </returns>
/// <seealso cref="Result" />
/// <seealso cref="SlashCommandAttribute" />
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(ISlashCommandContext context, IEnumerable<IDiscordInteractionOption>? options = null,
IServiceProvider? serviceProvider = null);
Task<Result<IDiscordInteractionResponse>> ExecuteSlashCommandAsync(
ISlashCommandContext context,
IEnumerable<IDiscordInteractionOption>? options = null,
IServiceProvider? serviceProvider = null
);

/// <summary>
/// Search for a command by its <see cref="SlashCommandAttribute.Name" />.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ public class SlashCommandBuildService : ISlashCommandBuildService
/// The <see cref="ISlashCommandOptionBuildService" /> that will get and build the
/// <see cref="ISlashCommandOptionInfo" />s.
/// </param>
public SlashCommandBuildService(ISlashCommandRequirementBuildService requirementBuildService, ISlashCommandGuildBuildService guildBuildService, ILogger<SlashCommandBuildService> logger,
ISlashCommandOptionBuildService optionBuildService)
public SlashCommandBuildService(
ISlashCommandRequirementBuildService requirementBuildService,
ISlashCommandGuildBuildService guildBuildService,
ILogger<SlashCommandBuildService> logger,
ISlashCommandOptionBuildService optionBuildService)
{
_requirementBuildService = requirementBuildService;
_guildBuildService = guildBuildService;
Expand All @@ -51,40 +54,45 @@ public SlashCommandBuildService(ISlashCommandRequirementBuildService requirement
}

/// <inheritdoc />
public IReadOnlyList<KeyValuePair<string, ISlashCommandInfo>> BuildSlashCommandInfos(Assembly assembly)
public IReadOnlyList<KeyValuePair<string, ISlashCommandInfo>> BuildSlashCommandInfos(params Assembly[] assemblies)
{
_logger.LogInformation("Loading interaction commands for assembly {AssemblyName}", assembly.FullName);
var validCommands = new List<KeyValuePair<string, ISlashCommandInfo>>();

foreach (var parentModule in GetSlashCommandModules(assembly))
foreach (var assembly in assemblies)
{
Comment thread
BrammyS marked this conversation as resolved.
if (IsValidCommandGroupModuleDefinition(parentModule))
_logger.LogInformation("Loading interaction commands for assembly {AssemblyName}", assembly.FullName);

foreach (var parentModule in GetSlashCommandModules(assembly))
Comment thread
BrammyS marked this conversation as resolved.
{
var groupAttribute = parentModule.GetCustomAttribute<SlashCommandGroupAttribute>();
if (groupAttribute is null)
if (IsValidCommandGroupModuleDefinition(parentModule))
{
_logger.LogWarning("Can not load command group {ModuleName} since it doesn't have the SlashCommandGroupAttribute attribute", parentModule.Name);
continue;
var groupAttribute = parentModule.GetCustomAttribute<SlashCommandGroupAttribute>();
if (groupAttribute is null)
{
_logger.LogWarning("Can not load command group {ModuleName} since it doesn't have the SlashCommandGroupAttribute attribute", parentModule.Name);
continue;
}

var commandInfoKeyValuePair = BuildCommandGroupInfoKeyValuePair(groupAttribute, parentModule);
validCommands.Add(commandInfoKeyValuePair);
_logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Key);
}

var commandInfoKeyValuePair = BuildCommandGroupInfoKeyValuePair(groupAttribute, parentModule);
validCommands.Add(commandInfoKeyValuePair);
_logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Key);
}

// The command is not a sub command / group.
// The command is not a sub command / group.

foreach (var validMethod in GetValidSlashCommandsMethods(parentModule))
{
var commandInfoKeyValuePair = BuildCommandInfoKeyValuePair(validMethod, parentModule);
foreach (var validMethod in GetValidSlashCommandsMethods(parentModule))
{
var commandInfoKeyValuePair = BuildCommandInfoKeyValuePair(validMethod, parentModule);

if (!commandInfoKeyValuePair.HasValue) continue;
validCommands.Add(commandInfoKeyValuePair.Value);
_logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Value.Key);
if (!commandInfoKeyValuePair.HasValue) continue;
validCommands.Add(commandInfoKeyValuePair.Value);
_logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Value.Key);
}
}

_logger.LogDebug("Found {CommandCount} valid commands in assembly {AssemblyName}", validCommands.Count.ToString(), assembly.FullName);
Comment thread
BrammyS marked this conversation as resolved.
}

_logger.LogDebug("Found {CommandCount} valid commands in assembly {AssemblyName}", validCommands.Count.ToString(), assembly.FullName);
return validCommands;
}

Expand Down Expand Up @@ -183,12 +191,12 @@ private KeyValuePair<string, ISlashCommandInfo> BuildCommandGroupInfoKeyValuePai
var commandRequirements = _requirementBuildService.GetCommandRequirements(rawValidCommand);
var options = _optionBuildService.GetCommandOptions(rawValidCommand);
var subCommand = new SlashCommandOptionInfo(subCommandAttribute.Name,
subCommandAttribute.Description,
subCommandAttribute.Acknowledge,
rawValidCommand,
parentModule,
commandRequirements,
options.ToList());
subCommandAttribute.Description,
subCommandAttribute.Acknowledge,
rawValidCommand,
parentModule,
commandRequirements,
options.ToList());

// Check if the command doesn't belong to a sub command group.
if (subCommandGroupAttribute is null)
Expand Down Expand Up @@ -235,8 +243,8 @@ private IEnumerable<MethodInfo> GetValidSlashCommandsMethods(Type parentModule)
if (IsValidCommandGroupModuleDefinition(parentModule)) return new List<MethodInfo>();

return parentModule
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(IsValidCommandDefinition);
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(IsValidCommandDefinition);
}

/// <summary>
Expand All @@ -251,8 +259,8 @@ private IEnumerable<MethodInfo> GetValidSubSlashCommandsMethods(Type parentModul
if (!IsValidCommandGroupModuleDefinition(parentModule)) return new List<MethodInfo>();

return parentModule
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(IsValidCommandDefinition);
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(IsValidCommandDefinition);
}

/// <summary>
Expand Down
Loading
Loading