27
27
import com .mojang .brigadier .exceptions .CommandSyntaxException ;
28
28
import com .mojang .brigadier .suggestion .SuggestionProvider ;
29
29
import com .mojang .brigadier .suggestion .Suggestions ;
30
+ import com .mojang .brigadier .tree .ArgumentCommandNode ;
31
+ import com .mojang .brigadier .tree .CommandNode ;
30
32
import com .mojang .brigadier .tree .LiteralCommandNode ;
31
33
import dev .jorel .commandapi .arguments .*;
32
34
import dev .jorel .commandapi .commandsenders .AbstractCommandSender ;
51
53
* @param <Source> The class for running Brigadier commands
52
54
*/
53
55
@ RequireField (in = CommandContext .class , name = "arguments" , ofType = Map .class )
56
+ @ RequireField (in = CommandNode .class , name = "children" , ofType = Map .class )
57
+ @ RequireField (in = CommandNode .class , name = "literals" , ofType = Map .class )
58
+ @ RequireField (in = CommandNode .class , name = "arguments" , ofType = Map .class )
54
59
public class CommandAPIHandler <Argument
55
60
/// @cond DOX
56
61
extends AbstractArgument <?, ?, Argument , CommandSender >
57
62
/// @endcond
58
63
, CommandSender , Source > {
64
+ // TODO: Need to ensure this can be safely "disposed of" when we're done (e.g. on reloads).
65
+ // I hiiiiiiighly doubt we're storing class caches of classes that can be unloaded at runtime,
66
+ // but this IS a generic class caching system and we don't want derpy memory leaks
67
+ private static final Map <ClassCache , Field > FIELDS ;
68
+
59
69
private static final SafeVarHandle <CommandContext <?>, Map <String , ParsedArgument <?, ?>>> commandContextArguments ;
70
+ // VarHandle seems incapable of setting final fields, so we have to use Field here
71
+ private static final Field commandNodeChildren ;
72
+ private static final Field commandNodeLiterals ;
73
+ private static final Field commandNodeArguments ;
60
74
61
- // Compute all var handles all in one go so we don't do this during main server
62
- // runtime
75
+ // Compute all var handles all in one go so we don't do this during main server runtime
63
76
static {
77
+ FIELDS = new HashMap <>();
78
+
64
79
commandContextArguments = SafeVarHandle .ofOrNull (CommandContext .class , "arguments" , "arguments" , Map .class );
80
+ commandNodeChildren = CommandAPIHandler .getField (CommandNode .class , "children" );
81
+ commandNodeLiterals = CommandAPIHandler .getField (CommandNode .class , "literals" );
82
+ commandNodeArguments = CommandAPIHandler .getField (CommandNode .class , "arguments" );
65
83
}
66
84
67
- // TODO: Need to ensure this can be safely "disposed of" when we're done (e.g. on reloads).
68
- // I hiiiiiiighly doubt we're storing class caches of classes that can be unloaded at runtime,
69
- // but this IS a generic class caching system and we don't want derpy memory leaks
70
- private static final Map <ClassCache , Field > FIELDS = new HashMap <>();
71
-
72
85
final CommandAPIPlatform <Argument , CommandSender , Source > platform ;
73
86
final List <RegisteredCommand > registeredCommands ; // Keep track of what has been registered for type checking
74
87
final Map <List <String >, Previewable <?, ?>> previewableArguments ; // Arguments with previewable chat
@@ -132,7 +145,7 @@ public CommandAPIPlatform<Argument, CommandSender, Source> getPlatform() {
132
145
// SECTION: Creating commands //
133
146
////////////////////////////////
134
147
135
- void registerCommand (ExecutableCommand <?, CommandSender > command ) {
148
+ public void registerCommand (ExecutableCommand <?, CommandSender > command ) {
136
149
platform .preCommandRegistration (command .getName ());
137
150
138
151
List <RegisteredCommand > registeredCommandInformation = RegisteredCommand .fromExecutableCommand (command );
@@ -422,6 +435,10 @@ public Predicate<Source> generateBrigadierRequirements(CommandPermission permiss
422
435
};
423
436
}
424
437
438
+ ////////////////////////////////
439
+ // SECTION: Brigadier Helpers //
440
+ ////////////////////////////////
441
+
425
442
public void writeDispatcherToFile () {
426
443
File file = CommandAPI .getConfiguration ().getDispatcherFile ();
427
444
if (file != null ) {
@@ -443,6 +460,54 @@ public void writeDispatcherToFile() {
443
460
}
444
461
}
445
462
463
+ public static <Source > Map <String , CommandNode <Source >> getCommandNodeChildren (CommandNode <Source > target ) {
464
+ try {
465
+ return (Map <String , CommandNode <Source >>) commandNodeChildren .get (target );
466
+ } catch (IllegalAccessException e ) {
467
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
468
+ }
469
+ }
470
+
471
+ public static <Source > void setCommandNodeChildren (CommandNode <Source > target , Map <String , CommandNode <Source >> children ) {
472
+ try {
473
+ commandNodeChildren .set (target , children );
474
+ } catch (IllegalAccessException e ) {
475
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
476
+ }
477
+ }
478
+
479
+ public static <Source > Map <String , LiteralCommandNode <Source >> getCommandNodeLiterals (CommandNode <Source > target ) {
480
+ try {
481
+ return (Map <String , LiteralCommandNode <Source >>) commandNodeLiterals .get (target );
482
+ } catch (IllegalAccessException e ) {
483
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
484
+ }
485
+ }
486
+
487
+ public static <Source > void setCommandNodeLiterals (CommandNode <Source > target , Map <String , LiteralCommandNode <Source >> literals ) {
488
+ try {
489
+ commandNodeLiterals .set (target , literals );
490
+ } catch (IllegalAccessException e ) {
491
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
492
+ }
493
+ }
494
+
495
+ public static <Source > Map <String , ArgumentCommandNode <Source , ?>> getCommandNodeArguments (CommandNode <Source > target ) {
496
+ try {
497
+ return (Map <String , ArgumentCommandNode <Source , ?>>) commandNodeArguments .get (target );
498
+ } catch (IllegalAccessException e ) {
499
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
500
+ }
501
+ }
502
+
503
+ public static <Source > void setCommandNodeArguments (CommandNode <Source > target , Map <String , ArgumentCommandNode <Source , ?>> arguments ) {
504
+ try {
505
+ commandNodeArguments .set (target , arguments );
506
+ } catch (IllegalAccessException e ) {
507
+ throw new IllegalStateException ("This shouldn't happen. The field should be accessible." , e );
508
+ }
509
+ }
510
+
446
511
////////////////////////////////
447
512
// SECTION: Parsing arguments //
448
513
////////////////////////////////
@@ -496,7 +561,7 @@ public static <CommandSource> String getRawArgumentInput(CommandContext<CommandS
496
561
* @return an CommandArguments object which can be used in (sender, args) ->
497
562
* @throws CommandSyntaxException If an argument is improperly formatted and cannot be parsed
498
563
*/
499
- CommandArguments argsToCommandArgs (CommandContext <Source > cmdCtx , List <Argument > args ) throws CommandSyntaxException {
564
+ public CommandArguments argsToCommandArgs (CommandContext <Source > cmdCtx , List <Argument > args ) throws CommandSyntaxException {
500
565
// Array for arguments for executor
501
566
List <Object > argList = new ArrayList <>();
502
567
@@ -538,7 +603,7 @@ CommandArguments argsToCommandArgs(CommandContext<Source> cmdCtx, List<Argument>
538
603
* @return the Argument's corresponding object
539
604
* @throws CommandSyntaxException when the input for the argument isn't formatted correctly
540
605
*/
541
- Object parseArgument (CommandContext <Source > cmdCtx , String key , Argument value , CommandArguments previousArgs ) throws CommandSyntaxException {
606
+ public Object parseArgument (CommandContext <Source > cmdCtx , String key , Argument value , CommandArguments previousArgs ) throws CommandSyntaxException {
542
607
if (value .isListed ()) {
543
608
return value .parseArgument (cmdCtx , key , previousArgs );
544
609
} else {
0 commit comments