Add support for registering subcommands by instance.

This commit introduces a new `register()` method on the CommandHandler
class to allow registering pre-instantiated subcommands. This means that
subcommands are no longer restricted in terms of instantiation, so they
can have their dependencies injected at creation, rather than having to
resort to Singleton anti-pattern means.

Also refactors the existing internal MobArena command registration to
use the new method to "drink our own champagne" and to reuse the code.

Fixes #675
This commit is contained in:
Andreas Troelsen 2021-07-01 21:30:00 +02:00
parent 614da20df8
commit 903752d23a
2 changed files with 30 additions and 7 deletions

View File

@ -11,6 +11,9 @@ These changes will (most likely) be included in the next version.
## [Unreleased]
### Added
- (API) MobArena's internal command handler now supports registering pre-instantiated subcommand instances. This should make it easier for extensions to avoid the Singleton anti-pattern for command dependencies.
### Changed
- The regex pattern for the player list command is now less greedy, so it will only match on `/ma players`, `/ma playerlist`, and `/ma player-list`. The previous pattern matched on anything that starts with `player`, which rendered the `/ma player-stats` command in MobArenaStats impossible to invoke.

View File

@ -349,14 +349,34 @@ public class CommandHandler implements CommandExecutor, TabCompleter
* @param c a Command
*/
public void register(Class<? extends Command> c) {
CommandInfo info = c.getAnnotation(CommandInfo.class);
if (info == null) return;
try {
commands.put(info.pattern(), c.newInstance());
}
catch (Exception e) {
e.printStackTrace();
Command command = c.newInstance();
register(command);
} catch (ReflectiveOperationException e) {
throw new IllegalArgumentException("Failed to instantiate Command class: " + c.getName(), e);
}
}
/**
* Register a command instance.
* <p>
* Adds the given command to MobArena's internal command handler as a
* subcommand, overwriting any existing subcommand mappings. This means
* that the method is safe to call on reloads as long as a reload does
* not change the pattern of a registered command.
*
* @param command the Command instance to register
* @throws IllegalArgumentException if the CommandInfo annotation is
* missing from the class of the Command instance
*/
public void register(Command command) {
Class<?> cls = command.getClass();
CommandInfo info = cls.getAnnotation(CommandInfo.class);
if (info == null) {
throw new IllegalArgumentException("Missing CommandInfo annotation on class " + cls.getName());
}
commands.put(info.pattern(), command);
}
}