Skip to content

Commit c555ca0

Browse files
committed
Fixed so you can register several main/root commands correcly
Now will it have option register own main commands with own sub commands.
1 parent 084c904 commit c555ca0

10 files changed

Lines changed: 735 additions & 34 deletions

File tree

Commands/src/main/java/org/broken/arrow/library/command/CommandRegister.java

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,41 @@
44
import org.broken.arrow.library.command.command.CommandProperty;
55
import org.broken.arrow.library.command.commandhandler.CommandExecutor;
66
import org.broken.arrow.library.command.commandhandler.CommandRegistering;
7+
import org.broken.arrow.library.command.commandhandler.MainCommandHandler;
8+
import org.broken.arrow.library.command.builers.CommandBuilder;
9+
import org.broken.arrow.library.command.subcommand.CommandDisplayConfig;
710
import org.broken.arrow.library.logging.Logging;
811
import org.bukkit.Bukkit;
912
import org.bukkit.command.Command;
1013
import org.bukkit.command.CommandException;
1114
import org.bukkit.command.CommandMap;
15+
import org.bukkit.plugin.Plugin;
1216

17+
import javax.annotation.Nonnull;
18+
import javax.annotation.Nullable;
1319
import java.lang.reflect.Field;
1420
import java.util.ArrayList;
1521
import java.util.Arrays;
1622
import java.util.Collections;
1723
import java.util.Comparator;
1824
import java.util.List;
25+
import java.util.Locale;
26+
import java.util.Map;
1927
import java.util.Objects;
2028
import java.util.Set;
29+
import java.util.concurrent.ConcurrentHashMap;
2130

2231
/**
2332
* A utility class for registering and managing registered commands.The commandRegister provides
2433
* methods for registering subcommands, setting command label messages and permissions,
2534
* retrieving sub-commands, and registering the main command label.
2635
*/
2736
public class CommandRegister implements CommandRegistering {
28-
private Logging log = new Logging(CommandRegister.class);
37+
private final Logging log = new Logging(CommandRegister.class);
2938

3039
private final List<CommandProperty> commands = Collections.synchronizedList(new ArrayList<>());
40+
private final Map<String, MainCommandHandler> commandsNew = new ConcurrentHashMap<>();
41+
3142
private String commandLabelMessage;
3243
private String commandLabelMessageNoPerms;
3344
private String commandLabelPermission;
@@ -43,7 +54,6 @@ public CommandRegistering registerSubCommand(final CommandProperty subCommand) {
4354
if (addCommands(subCommand, commandLabels)) {
4455
return this;
4556
}
46-
4757
commands.removeIf(oldCommandBuilder -> oldCommandBuilder.equals(subCommand));
4858
commands.removeIf(oldCommandBuilder -> oldCommandBuilder.getCommandLabels().equals(subCommand.getCommandLabels()));
4959
commands.add(subCommand);
@@ -58,9 +68,49 @@ public CommandRegistering registerSubCommands(final CommandProperty... subComman
5868
for (CommandProperty registerSubCommand : subCommands) {
5969
this.registerSubCommand(registerSubCommand);
6070
}
71+
72+
registerCommand(null, "test")
73+
.setAliases("before")
74+
.registerSubCommandGroup(subCommand->{
75+
subCommand.registerSubCommand(null);
76+
})
77+
.display(displayConfig -> {
78+
displayConfig.setCommandLabelMessage("");
79+
displayConfig.setSuffixMessage("-----<suffix>-----");
80+
displayConfig.setPrefixMessage("-----<prefix>-----");
81+
})
82+
.setAliases("testings");
83+
84+
registerCommand(null, "testing")
85+
.setMainDescription("something")
86+
.setMainCommand(null)
87+
.setMainDescription("a command");
6188
return this;
6289
}
6390

91+
/**
92+
* Registers a new command entry point for this plugin.
93+
*
94+
* <p>This is the primary entry method for creating and configuring a command.
95+
* It initializes the internal command handler and returns a {@link CommandBuilder}
96+
* used to define aliases, subcommands, execution behavior, and display settings.</p>
97+
*
98+
* <p>The plugin name is used as a fallback namespace for command registration.</p>
99+
*
100+
* @param plugin the owning plugin instance (used for namespace and registration context)
101+
* @param mainCommand the root command label (e.g. "plugin" in "/plugin menu")
102+
* @return a {@link CommandBuilder} used to configure the command structure
103+
*/
104+
public CommandBuilder registerCommand(final Plugin plugin, final String mainCommand) {
105+
final CommandDisplayConfig commandDisplayConfig = new CommandDisplayConfig();
106+
final MainCommandHandler mainCommandHandler = new MainCommandHandler(commandDisplayConfig);
107+
final CommandBuilder commandBuilder = new CommandBuilder(mainCommandHandler);
108+
109+
commandsNew.put(mainCommand, mainCommandHandler);
110+
this.registerMainCommand(plugin.getName().toLowerCase(Locale.ROOT), mainCommand, commandBuilder);
111+
return commandBuilder;
112+
}
113+
64114
/**
65115
* Returns the message to display as the command label.
66116
*
@@ -260,6 +310,7 @@ public List<CommandProperty> getCommands() {
260310
* @param label The sub-label of the command builder to retrieve.
261311
* @return The command builder with the specified sub-label, or null if not found.
262312
*/
313+
@Nullable
263314
@Override
264315
public CommandProperty getCommandBuilder(String label) {
265316
return getCommandBuilder(label, false);
@@ -272,8 +323,11 @@ public CommandProperty getCommandBuilder(String label) {
272323
* @param startsWith Specifies whether the sub-label should match the beginning of the command builder's sub-label.
273324
* @return The command builder with the specified sub-label, or null if not found.
274325
*/
326+
@Nullable
275327
@Override
276328
public CommandProperty getCommandBuilder(String label, boolean startsWith) {
329+
if (startsWith)
330+
System.out.println("getCommandBuilder " + label);
277331
for (final CommandProperty command : commands) {
278332
if (startsWith && (label.isEmpty() || command.firstLabelMatch(label, true) != null))
279333
return command;
@@ -310,6 +364,7 @@ public CommandRegistering registerMainCommand(String fallbackPrefix, String main
310364
return this.registerMainCommand(fallbackPrefix, mainCommand, "", "", aliases);
311365
}
312366

367+
313368
/**
314369
* Registers the main command with the specified fallback prefix, command, description, usage message, and aliases.
315370
* If the main command has already been registered, this method does nothing.
@@ -322,16 +377,14 @@ public CommandRegistering registerMainCommand(String fallbackPrefix, String main
322377
* @return The CommandRegistering instance.
323378
*/
324379
@Override
325-
public CommandRegistering registerMainCommand(String fallbackPrefix, String mainCommand, String description, String usageMessage, String... aliases) {
380+
public CommandRegistering registerMainCommand(@Nonnull final String fallbackPrefix, @Nonnull final String mainCommand, @Nonnull final String description, @Nonnull final String usageMessage, @Nonnull final String... aliases) {
326381
final String[] main = mainCommand.split("\\|");
327382
if (registeredMainCommand) return this;
328383
if (main.length > 1)
329384
for (final String command : main)
330385
this.register(fallbackPrefix, new CommandExecutor(this, command, description, usageMessage, Arrays.asList(aliases)));
331386
else
332387
this.register(fallbackPrefix, new CommandExecutor(this, mainCommand, description, usageMessage, Arrays.asList(aliases)));
333-
registeredMainCommand = true;
334-
335388
return this;
336389
}
337390

@@ -350,6 +403,14 @@ public boolean addCommands(CommandProperty subCommand, Set<String> commandLabels
350403
}
351404
}
352405

406+
private void registerMainCommand(@Nonnull final String fallbackPrefix, @Nonnull final String mainCommand, @Nonnull final CommandBuilder commandBuilder) {
407+
final String description = commandBuilder.getMainDescription();
408+
final String usageMessage = commandBuilder.getMainUsageMessage();
409+
final String[] aliases = commandBuilder.getAliases();
410+
this.registerMainCommand(fallbackPrefix, mainCommand, description, usageMessage, aliases);
411+
}
412+
413+
353414
/**
354415
* Registers the specified command with the provided fallback prefix.
355416
* This method uses reflection to access the commandMap and register the command.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package org.broken.arrow.library.command.builers;
2+
3+
import org.broken.arrow.library.command.command.CommandProperty;
4+
import org.broken.arrow.library.command.commandhandler.MainCommandHandler;
5+
import org.broken.arrow.library.logging.Validate;
6+
import org.bukkit.command.CommandException;
7+
8+
import javax.annotation.Nonnull;
9+
import java.util.function.Consumer;
10+
11+
/**
12+
* Entry builder for defining a command structure, including optional subcommands,
13+
* a single main command, and shared command metadata such as aliases, usage, and description.
14+
*
15+
* <p>This class represents the primary configuration stage of a command before it transitions
16+
* into execution-specific or display configuration stages.</p>
17+
*/
18+
public class CommandBuilder extends CommandOptions {
19+
private final MainCommandHandler mainCommandHandler;
20+
21+
/**
22+
* Creates a new command builder tied to the given {@link MainCommandHandler}.
23+
*
24+
* @param mainCommandHandler internal handler responsible for managing command registration
25+
*/
26+
public CommandBuilder(@Nonnull final MainCommandHandler mainCommandHandler) {
27+
this.mainCommandHandler = mainCommandHandler;
28+
}
29+
30+
/**
31+
* Sets the command description.
32+
*
33+
* @param description human-readable description of the command
34+
* @return this builder instance for chaining
35+
*/
36+
@Override
37+
public CommandBuilder setMainDescription(String description) {
38+
super.setMainDescription(description);
39+
return this;
40+
}
41+
42+
/**
43+
* Sets the usage message displayed when the command is used incorrectly or help is requested.
44+
*
45+
* @param usageMessage usage instruction string
46+
* @return this builder instance for chaining
47+
*/
48+
@Override
49+
public CommandBuilder setMainUsageMessage(String usageMessage) {
50+
super.setMainUsageMessage(usageMessage);
51+
return this;
52+
}
53+
54+
/**
55+
* Defines alternative aliases for this command.
56+
*
57+
* @param aliases alternative command labels
58+
* @return this builder instance for chaining
59+
*/
60+
@Override
61+
public CommandBuilder setAliases(String... aliases) {
62+
super.setAliases(aliases);
63+
return this;
64+
}
65+
66+
/**
67+
* Registers a group of subcommands using a configuration wrapper.
68+
*
69+
* <p>This method provides a structured way to define multiple subcommands
70+
* within a single lambda scope, improving readability and reducing repeated calls.</p>
71+
*
72+
* <pre>{@code
73+
* registerSubCommandGroup(wrapper -> {
74+
* wrapper.registerSubCommand(new ReloadCommand(...));
75+
* wrapper.registerSubCommand(new HelpCommand(...));
76+
* });
77+
* }</pre>
78+
*
79+
* @param consumer lambda receiving a {@link SubcommandWrapper} used to register subcommands
80+
* @return a {@link CommandDisplayBuilder} to continue configuration (e.g. display settings)
81+
* @throws CommandException if any subcommand has invalid or empty command labels
82+
*/
83+
public CommandDisplayBuilder registerSubCommandGroup(@Nonnull final Consumer<SubcommandWrapper> consumer) {
84+
final SubcommandWrapper subcommandWrapper = new SubcommandWrapper(mainCommandHandler);
85+
consumer.accept(subcommandWrapper);
86+
return new CommandDisplayBuilder(this, mainCommandHandler);
87+
}
88+
89+
/**
90+
* Registers one or more subcommands directly using varargs input.
91+
*
92+
* <p>This is a convenience method for quickly registering multiple subcommands
93+
* without using a lambda-based configuration block.</p>
94+
*
95+
* @param subCommands subcommands to register (must not be null or empty)
96+
* @return a {@link CommandDisplayBuilder} to continue configuration (e.g. display settings)
97+
* @throws CommandException if any subcommand has invalid or empty command labels
98+
* @throws Validate.ValidateExceptions if a main command has already been configured
99+
*/
100+
public CommandDisplayBuilder registerSubCommands(final CommandProperty... subCommands) {
101+
mainCommandHandler.registerSubCommands(subCommands);
102+
return new CommandDisplayBuilder(this, mainCommandHandler);
103+
}
104+
105+
/**
106+
* Defines a single main command instead of using subcommands.
107+
*
108+
* <p>This mode is mutually exclusive with subcommand registration.</p>
109+
*
110+
* @param mainCommand the main command definition
111+
* @return this builder instance for further configuration
112+
* @throws Validate.ValidateExceptions if subcommands have already been registered
113+
*/
114+
public CommandOptions setMainCommand(@Nonnull final CommandProperty mainCommand) {
115+
mainCommandHandler.setMainCommand(mainCommand);
116+
return this;
117+
}
118+
119+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.broken.arrow.library.command.builers;
2+
3+
import org.broken.arrow.library.command.commandhandler.MainCommandHandler;
4+
import org.broken.arrow.library.command.subcommand.CommandDisplayConfig;
5+
6+
7+
import javax.annotation.Nonnull;
8+
import java.util.function.Consumer;
9+
10+
/**
11+
* Final configuration stage for applying display-related settings
12+
* to a command before returning to the main configuration flow.
13+
*
14+
* <p>This stage is typically entered after subcommand registration.</p>
15+
*/
16+
public class CommandDisplayBuilder {
17+
private final CommandBuilder commandRegister;
18+
private final MainCommandHandler mainCommandHandler;
19+
20+
/**
21+
* Creates a new display builder.
22+
*
23+
* @param commandRegister parent command builder
24+
* @param mainCommandHandler internal command handler
25+
*/
26+
public CommandDisplayBuilder(@Nonnull final CommandBuilder commandRegister, @Nonnull final MainCommandHandler mainCommandHandler) {
27+
this.commandRegister = commandRegister;
28+
this.mainCommandHandler = mainCommandHandler;
29+
}
30+
31+
/**
32+
* Applies display configuration to the command.
33+
*
34+
* <p>This includes messages, prefixes, suffixes, and other visual output
35+
* shown when interacting with the command system.</p>
36+
*
37+
* <pre>{@code
38+
* display(config -> {
39+
* config.setPrefixMessage("...");
40+
* config.setSuffixMessage("...");
41+
* });
42+
* }</pre>
43+
*
44+
* @param callback consumer used to configure {@link CommandDisplayConfig}
45+
* @return the original {@link CommandOptions} builder to continue configuration
46+
*/
47+
public CommandOptions display(final Consumer<CommandDisplayConfig> callback) {
48+
callback.accept(mainCommandHandler.getCommandDisplayConfig());
49+
return commandRegister;
50+
}
51+
52+
}

0 commit comments

Comments
 (0)