@@ -55,6 +55,12 @@ public class CommandFramework implements CommandExecutor, TabCompleter {
55
55
@ NotNull
56
56
private final Map <Command , Map .Entry <Method , Object >> commands = new HashMap <>();
57
57
58
+ /**
59
+ * Map of registered subcommands by framework.
60
+ */
61
+ @ NotNull
62
+ private final Map <Command , Map .Entry <Method , Object >> subCommands = new HashMap <>();
63
+
58
64
/**
59
65
* Map of registered tab completions by framework.
60
66
*/
@@ -134,15 +140,18 @@ public void registerCommands(@NotNull Object instance) {
134
140
* @param instance of the method above
135
141
*/
136
142
private void registerCommand (Command command , Method method , Object instance ) {
137
- commands .put (command , me .despical .commons .util .Collections .mapEntry (method , instance ));
143
+ if (command .name ().contains ("." )) {
144
+ subCommands .put (command , me .despical .commons .util .Collections .mapEntry (method , instance ));
145
+ } else {
146
+ commands .put (command , me .despical .commons .util .Collections .mapEntry (method , instance ));
147
+ }
138
148
139
149
try {
140
150
final Constructor <PluginCommand > constructor = PluginCommand .class .getDeclaredConstructor (String .class , Plugin .class );
141
151
constructor .setAccessible (true );
142
152
143
153
final String splittedCommand = command .name ().split ("\\ ." )[0 ];
144
-
145
- final PluginCommand pluginCommand = constructor .newInstance (splittedCommand , plugin );
154
+ final PluginCommand pluginCommand = constructor .newInstance (splittedCommand , plugin );
146
155
pluginCommand .setTabCompleter (this );
147
156
pluginCommand .setExecutor (this );
148
157
pluginCommand .setUsage (command .usage ());
@@ -156,6 +165,44 @@ private void registerCommand(Command command, Method method, Object instance) {
156
165
}
157
166
}
158
167
168
+ @ Nullable
169
+ private Map .Entry <Command , Map .Entry <Method , Object >> getAssociatedCommand (@ NotNull String commandName , @ NotNull String [] possibleArgs ) {
170
+ Command command = null ;
171
+
172
+ // Search for the sub commands first
173
+ for (Command cmd : subCommands .keySet ()) {
174
+ final String name = cmd .name (), cmdName = commandName + (possibleArgs .length == 0 ? "" : "." + String .join ("." , Arrays .copyOfRange (possibleArgs , 0 , name .split ("\\ ." ).length - 1 )));
175
+
176
+ if (name .equalsIgnoreCase (cmdName ) || Stream .of (cmd .aliases ()).anyMatch (commandName ::equalsIgnoreCase )) {
177
+ command = cmd ;
178
+ break ;
179
+ }
180
+ }
181
+
182
+ // If we found the sub command then return it, otherwise search the commands map
183
+ if (command != null ) {
184
+ return me .despical .commons .util .Collections .mapEntry (command , subCommands .get (command ));
185
+ }
186
+
187
+ // If our command is not a sub command then search for a main command
188
+ for (Command cmd : commands .keySet ()) {
189
+ final String name = cmd .name ();
190
+
191
+ if (name .equalsIgnoreCase (commandName ) || Stream .of (cmd .aliases ()).anyMatch (commandName ::equalsIgnoreCase )) {
192
+ command = cmd ;
193
+ break ;
194
+ }
195
+ }
196
+
197
+ // If we found the command return it, otherwise return null
198
+ if (command != null ) {
199
+ return me .despical .commons .util .Collections .mapEntry (command , commands .get (command ));
200
+ }
201
+
202
+ // Return null if the given command is not registered by Command Framework
203
+ return null ;
204
+ }
205
+
159
206
// Error Message Handler
160
207
161
208
public static String ONLY_BY_PLAYERS = ChatColor .RED + "This command is only executable by players!" ;
@@ -166,61 +213,59 @@ private void registerCommand(Command command, Method method, Object instance) {
166
213
167
214
@ Override
168
215
public boolean onCommand (@ NotNull CommandSender sender , @ NotNull org .bukkit .command .Command cmd , @ NotNull String label , String [] args ) {
169
- for (Map .Entry <Command , Map .Entry <Method , Object >> entry : commands .entrySet ()) {
170
- final Command command = entry .getKey ();
171
- final String splitted [] = command .name ().split ("\\ ." ), allArgs = args .length == 0 ? "" : String .join ("." , Arrays .copyOfRange (args , 0 , splitted .length - 1 ));
172
- final String cmdName = (command .name ().contains ("." ) ? splitted [0 ] : cmd .getName ()) + (splitted .length == 1 && allArgs .isEmpty () ? "" : "." + allArgs );
173
-
174
- if (command .name ().equalsIgnoreCase (cmdName ) || Stream .of (command .aliases ()).anyMatch (cmdName ::equalsIgnoreCase )) {
175
- if (!sender .hasPermission (command .permission ())) {
176
- sender .sendMessage (NO_PERMISSION );
177
- return true ;
178
- }
216
+ Map .Entry <Command , Map .Entry <Method , Object >> entry = this .getAssociatedCommand (cmd .getName (), args );
179
217
180
- if (command .senderType () == Command .SenderType .PLAYER && !(sender instanceof Player )) {
181
- sender .sendMessage (ONLY_BY_PLAYERS );
182
- return true ;
183
- }
218
+ if (entry == null ) {
219
+ return true ;
220
+ } else {
221
+ if (anyMatchConsumer != null ) {
222
+ anyMatchConsumer .accept (new CommandArguments (sender , cmd , label , args ));
223
+ return true ;
224
+ }
225
+ }
184
226
185
- if (command .senderType () == Command .SenderType .CONSOLE && sender instanceof Player ) {
186
- sender .sendMessage (ONLY_BY_CONSOLE );
187
- return true ;
188
- }
227
+ Command command = entry .getKey ();
189
228
190
- if (cooldowns .containsKey (sender )) {
191
- if (command .cooldown () > 0 && ((System .currentTimeMillis () - cooldowns .get (sender )) / 1000 ) % 60 <= command .cooldown ()) {
192
- sender .sendMessage (WAIT_BEFORE_USING_AGAIN );
193
- return true ;
194
- } else {
195
- cooldowns .remove (sender );
196
- }
197
- } else {
198
- cooldowns .put (sender , System .currentTimeMillis ());
199
- }
229
+ if (!sender .hasPermission (command .permission ())) {
230
+ sender .sendMessage (NO_PERMISSION );
231
+ return true ;
232
+ }
200
233
201
- final String [] newArgs = Arrays .copyOfRange (args , splitted .length - 1 , args .length );
202
-
203
- if (args .length >= command .min () + splitted .length - 1 && newArgs .length <= (command .max () == -1 ? newArgs .length + 1 : command .max ())) {
204
- try {
205
- entry .getValue ().getKey ().invoke (entry .getValue ().getValue (), new CommandArguments (sender , cmd , label , newArgs ));
206
- return true ;
207
- } catch (IllegalAccessException | InvocationTargetException e ) {
208
- e .printStackTrace ();
209
- return true ;
210
- }
211
- } else {
212
- sender .sendMessage (SHORT_OR_LONG_ARG_SIZE );
213
- return true ;
214
- }
215
- }
234
+ if (command .senderType () == Command .SenderType .PLAYER && !(sender instanceof Player )) {
235
+ sender .sendMessage (ONLY_BY_PLAYERS );
236
+ return true ;
216
237
}
217
238
218
- if (anyMatchConsumer != null ) {
219
- anyMatchConsumer . accept ( new CommandArguments ( sender , cmd , label , args ) );
239
+ if (command . senderType () == Command . SenderType . CONSOLE && sender instanceof Player ) {
240
+ sender . sendMessage ( ONLY_BY_CONSOLE );
220
241
return true ;
221
242
}
222
243
223
- return false ;
244
+ if (cooldowns .containsKey (sender )) {
245
+ if (command .cooldown () > 0 && ((System .currentTimeMillis () - cooldowns .get (sender )) / 1000 ) % 60 <= command .cooldown ()) {
246
+ sender .sendMessage (WAIT_BEFORE_USING_AGAIN );
247
+ return true ;
248
+ } else {
249
+ cooldowns .remove (sender );
250
+ }
251
+ } else {
252
+ cooldowns .put (sender , System .currentTimeMillis ());
253
+ }
254
+
255
+ final String [] splitted = command .name ().split ("\\ ." ), newArgs = Arrays .copyOfRange (args , splitted .length - 1 , args .length );
256
+
257
+ if (args .length >= command .min () + splitted .length - 1 && newArgs .length <= (command .max () == -1 ? newArgs .length + 1 : command .max ())) {
258
+ try {
259
+ entry .getValue ().getKey ().invoke (entry .getValue ().getValue (), new CommandArguments (sender , cmd , label , newArgs ));
260
+ return true ;
261
+ } catch (IllegalAccessException | InvocationTargetException e ) {
262
+ e .printStackTrace ();
263
+ return true ;
264
+ }
265
+ } else {
266
+ sender .sendMessage (SHORT_OR_LONG_ARG_SIZE );
267
+ return true ;
268
+ }
224
269
}
225
270
226
271
@ Override
@@ -243,12 +288,15 @@ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull org.bu
243
288
}
244
289
245
290
/**
246
- * Get the copied list of registered commands.
291
+ * Get the copied list of registered commands and subcommands .
247
292
*
248
- * @return list of commands.
293
+ * @return list of commands and subcommands .
249
294
*/
250
295
@ NotNull
251
296
public List <Command > getCommands () {
252
- return new ArrayList <>(commands .keySet ());
297
+ List <Command > commands = new ArrayList <>(this .commands .keySet ());
298
+ commands .addAll (subCommands .keySet ());
299
+
300
+ return commands ;
253
301
}
254
302
}
0 commit comments