Remora / Remora.Discord

A data-oriented C# Discord library, focused on high-performance concurrency and robust design.
GNU Lesser General Public License v3.0
246 stars 44 forks source link

[Bug]: Nested command groups causes un-nested registrations #298

Open VelvetToroyashi opened 1 year ago

VelvetToroyashi commented 1 year ago

Description

When registering a nested slash command group, the child group is un-nested at runtime.

Steps to Reproduce

Register the following with Remora.Discord.Commands

[Group("parent")]
public class ParentGroup : CommandGroup
{
  [Group("child")]
  public class ChildGroup : CommandGroup
  {
    [Command("command")]
    public async Task<Result> CommandAsync() => Result.FromSuccess();
  }
}

Expected Behavior

The command is registered with discord as `/parent child command.

This is represented as Command ➜ Subcommand-group ➜ Subcommand

Current Behavior

The command is in fact registered in this manner, but is also duplicated, eliding the parent.

This is illustrated in this screenshot: image

Top: Command ➜ Subommand (Incorrect) Bottom: Command ➜ Subcommand-group ➜ Command (Correct)

This is a bug in Remora's translation from Command tree ➜ Application command tree, however executing the malformed command still appears to work correctly

Library / Runtime Information

C# 11 .NET 7.0.2 Remora.Discord.Commands 26.2.3

Nihlus commented 1 year ago

I don't think this is a Remora issue, because I have several groups with this setup that work just fine. Make sure you're not registering the inner group by itself, either explicitly or via assembly scanning.

VelvetToroyashi commented 1 year ago

Hmm. Seems to be an issue with the assembly scanning code, since there isn't a check for nested children in groups

https://github.com/Remora/Remora.Discord/blob/3818e52/Remora.Discord.Extensions/Extensions/ServiceCollectionExtensions.cs#L71-L77

VelvetToroyashi commented 1 year ago

Also following up on this (has it really been three days already?), I can confirm that adding t => !t.IsNested as a type filter works image

Thank goodness making extensible APIs.