Skip to content

Commit 4b8bd23

Browse files
committed
Improve brigadier command-mapping and fix issues with suggestions
1 parent 414e3c8 commit 4b8bd23

File tree

5 files changed

+76
-46
lines changed

5 files changed

+76
-46
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ run/*
3030

3131
.idea
3232
*/.idea
33+
34+
fabric-test-mod

bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/BrigadierBridge.java

Lines changed: 63 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -84,54 +84,58 @@ private static <C, D, T> Collection<CommandNode<D>> createCommandNodes(
8484

8585
LiteralArgumentBuilder<D> builder = LiteralArgumentBuilder.literal(((LiteralCommand<C, T>) node).getLiteral());
8686
builder.requires(d -> node.isValid(contextConverter.apply(d)));
87-
builder.executes(executor);
88-
89-
for (Command<C, ?> subCommand : node.getSubCommands()) {
90-
createCommandNodes(List.of(subCommand), suggestionProvider, executor, contextConverter).forEach(builder::then);
91-
}
87+
if (node.getExecutable() != null) builder.executes(executor);
88+
createCommandNodes(node.getSubCommands(), suggestionProvider, executor, contextConverter).forEach(builder::then);
9289

9390
commandNodes.add(builder.build());
9491
}
9592

96-
// arguments
97-
Set<ArgumentCommand<C, T>> argumentNodes = nodes.stream()
98-
.filter(n -> n instanceof ArgumentCommand)
99-
.map(n -> (ArgumentCommand<C, T>) n)
100-
.collect(Collectors.toSet());
101-
102-
if (!argumentNodes.isEmpty()) {
103-
CommonNodeType commonNodeType = argumentNodes.stream()
104-
.map(CommonNodeType::getFor)
105-
.max(Comparator.comparing(CommonNodeType::ordinal))
106-
.get();
107-
108-
String commonNodeName;
109-
if (argumentNodes.size() <= 3) {
110-
commonNodeName = commonNodeType == CommonNodeType.GREEDY ? "..." : argumentNodes.stream()
111-
.map(ArgumentCommand::getArgumentId)
112-
.sorted()
113-
.collect(Collectors.joining("|"));
114-
} else {
115-
commonNodeName = "arg-" + UUID.randomUUID().toString().substring(0, 8);
116-
}
117-
118-
RequiredArgumentBuilder<D, ?> builder = RequiredArgumentBuilder.argument(commonNodeName, commonNodeType.getArgumentType());
119-
builder.suggests(suggestionProvider);
120-
builder.requires(d -> {
121-
C context = contextConverter.apply(d);
122-
return argumentNodes.stream().anyMatch(arg -> arg.isValid(context));
123-
});
124-
builder.executes(executor);
125-
126-
if (commonNodeType != CommonNodeType.GREEDY) {
127-
Collection<Command<C, T>> subCommands = argumentNodes.stream()
128-
.flatMap(c -> c.getSubCommands().stream())
129-
.collect(Collectors.toSet());
130-
createCommandNodes(subCommands, suggestionProvider, executor, contextConverter).forEach(builder::then);
131-
}
132-
133-
commandNodes.add(builder.build());
134-
}
93+
// group arguments by brigadier-type
94+
// using an enum-map here sorts the arguments by their type as well (enum-ordinal) -> this is important
95+
EnumMap<CommonNodeType, Set<ArgumentCommand<C, T>>> typedArguments = nodes.stream()
96+
.filter(c -> c instanceof ArgumentCommand)
97+
.map(c -> (ArgumentCommand<C, T>) c)
98+
.collect(Collectors.groupingBy(
99+
CommonNodeType::getFor,
100+
() -> new EnumMap<>(CommonNodeType.class),
101+
Collectors.toSet()
102+
));
103+
104+
// group string-type arguments together further
105+
if (typedArguments.containsKey(CommonNodeType.WORD) && typedArguments.containsKey(CommonNodeType.STRING))
106+
typedArguments.get(CommonNodeType.STRING).addAll(typedArguments.remove(CommonNodeType.WORD));
107+
if (typedArguments.containsKey(CommonNodeType.STRING) && typedArguments.containsKey(CommonNodeType.GREEDY))
108+
typedArguments.get(CommonNodeType.GREEDY).addAll(typedArguments.remove(CommonNodeType.STRING));
109+
110+
typedArguments.forEach((type, arguments) -> {
111+
112+
RequiredArgumentBuilder<D, ?> builder = RequiredArgumentBuilder.argument(
113+
getCommonArgumentId(type, arguments),
114+
type.getArgumentType()
115+
);
116+
117+
// only allow suggestions for string-types
118+
if (type == CommonNodeType.GREEDY || type == CommonNodeType.STRING || type == CommonNodeType.WORD)
119+
builder.suggests(suggestionProvider);
120+
121+
builder.requires(d -> {
122+
C context = contextConverter.apply(d);
123+
return arguments.stream().anyMatch(arg -> arg.isValid(context));
124+
});
125+
126+
if (arguments.stream().map(Command::getExecutable).anyMatch(Objects::nonNull))
127+
builder.executes(executor);
128+
129+
if (type != CommonNodeType.GREEDY) {
130+
Collection<Command<C, T>> subCommands = arguments.stream()
131+
.flatMap(c -> c.getSubCommands().stream())
132+
.collect(Collectors.toSet());
133+
createCommandNodes(subCommands, suggestionProvider, executor, contextConverter).forEach(builder::then);
134+
}
135+
136+
commandNodes.add(builder.build());
137+
138+
});
135139

136140
return commandNodes;
137141
}
@@ -150,14 +154,28 @@ private static <C, T> void collectNodes(Command<C, T> command, Set<Command<C, T>
150154
nodes.add(command);
151155

152156
// handle optional commands
153-
if (command instanceof ArgumentCommand && ((ArgumentCommand<C, T>) command).isOptional()) {
157+
if (command.isOptional()) {
154158
for (var subCommand : command.getSubCommands()) {
155159
collectNodes(subCommand, nodes);
156160
}
157161
}
158162

159163
}
160164

165+
private static <C, T> String getCommonArgumentId(CommonNodeType type, Collection<ArgumentCommand<C, T>> arguments) {
166+
String commonNodeName;
167+
if (arguments.size() <= 3) {
168+
commonNodeName = type == CommonNodeType.GREEDY ? "..." : arguments.stream()
169+
.map(ArgumentCommand::getArgumentId)
170+
.distinct()
171+
.sorted()
172+
.collect(Collectors.joining("|"));
173+
} else {
174+
commonNodeName = "arg-" + UUID.randomUUID().toString().substring(0, 8);
175+
}
176+
return commonNodeName;
177+
}
178+
161179
private enum CommonNodeType {
162180

163181
INTEGER (LongArgumentType.longArg()),

bluecommands-brigadier/src/main/java/de/bluecolored/bluecommands/brigadier/CommandSuggestionProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.HashMap;
3434
import java.util.Map;
3535
import java.util.concurrent.CompletableFuture;
36+
import java.util.concurrent.TimeUnit;
3637
import java.util.function.Function;
3738

3839
class CommandSuggestionProvider<D> implements SuggestionProvider<D> {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

settings.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1+
pluginManagement {
2+
repositories {
3+
gradlePluginPortal()
4+
mavenCentral()
5+
maven ("https://maven.fabricmc.net/" )
6+
}
7+
}
8+
19
rootProject.name = "BlueCommands"
210

311
include("bluecommands-core")
412
include("bluecommands-brigadier")
13+
//include("fabric-test-mod")

0 commit comments

Comments
 (0)