Improvement in CommandSpec registeration?

Before I begin, I didn’t already forked and added this to my fork because I wasn’t sure if people would like the concept. However if it is liked, I would love to implement this. :slight_smile: If not, then well …


Currently the way commands are built and then registered are as follows:

This may work well with plugins that have few commands. However for plugins that have a strong base in commands such as EssentialCmds or Core where there are >60 commands, this format becomes a kind of a boilerplate code. For example EssentialCmds has atleast 100 CommandSpecs excluding those which are register as children of other commands. That means the plugin developer has to make a CommandSpec and THEN register them. That’s a lot of boilercode.


My suggestion:

My suggestion is to add an @CommandSpecifier(aliases:String[]) annotation for fields. The way this would work would be similar to how @Listener works, scanning for methods in a registered class, except for fields. Then reflection can be used to get all the fields and scan for @CommandSpecifier annotation. If present, register the CommandSpec with the aliases given in the annotation.

For example

This way you just specify the various classes that define CommandSpec/CommandCallables and Sponge autoregisters them for you.

2 Likes

I think this idea could help with large plugins having to write lots of boilerplate code. Good idea!

I don’t see it being any better. You’re still writing boilerplate code. You have to write:

@CommandSpecifier("inscrutable", "poet") private CommandSpec inscrutableThePoet = CommandSpec.builder.description(Text.of("I love Insrutable's poetry!").executor(...).build();

as opposed to:

Sponge.getCommandManager().register(plugin, CommandSpec.builder.description(Text.of("I love Insrutable's poetry!").executor(...).build(), "inscrutable", "poet");

each time. Whatever way you look at it, you still have to write the CommandSpec and provide aliases each time, there isn’t much of a way around it unless you go to a full annotation based system, where the executor is annotated with all the relavant information.

I understand it’s a problem, but there are ways to manage it. For example, I tried to make it more managable in EssentialCmds by creating a common base class for all commands (CommandExecutorBase) and wrote a loader for it to avoid writing some of the boilerplate code. It’s something I do in my own codes too, and I figured I’d give back to a popular plugin. Maybe that’s something that could be done within the API, provide another class or interface like CommandExecutorBase that provides methods for retireving aliases and CommandSpecs, and then just pass the class to the manager. Maybe they can be annotated.

However, simply having an annotation as you suggest doesn’t strike me as adding anything to the API - it’s just another way to specify a command in just as many characters.

1 Like

The main purpose of this way was not to prevent the writing of the whole CommandSpec, but instead preventing the Sponge.getCommandManager().register() line.

I know, but you have to write just as much to specify the annotation - in fact, even more than the register line, because you have to specify the annotation on the variable and THEN register the class, in your example. You end up writing more, not less - defeating the object of writing less boilerplate code.

It just feels to me that this is a problem that plugins have to solve if they want to solve it, rather than the API in its current form. I did it for EssentialCmds, the register line is specified for code once - but to be honest, it involved writing more code rather than less.