Repository navigation
Expand file tree
/
Copy pathCommandGuard.java
More file actions
73 lines (67 loc) · 3.33 KB
/
Copy pathCommandGuard.java
File metadata and controls
73 lines (67 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.minecraftcitiesnetwork.pluginInfrastructure.modules;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
import java.util.function.BooleanSupplier;
/**
* Rebuilds a module's command tree so that every executor and suggestion provider first checks
* whether the module is active. Brigadier nodes are immutable once built, so the guard is applied
* by rebuilding each node from {@link CommandNode#createBuilder()}.
*/
final class CommandGuard {
private CommandGuard() {
}
// Rebuilding a literal yields a literal, and an argument node's builder is a RequiredArgumentBuilder.
@SuppressWarnings("unchecked")
static @NotNull LiteralCommandNode<CommandSourceStack> guard(
@NotNull LiteralArgumentBuilder<CommandSourceStack> command,
@NotNull String moduleName,
@NotNull BooleanSupplier active,
@NotNull ModuleUnavailableHandler unavailable
) {
return (LiteralCommandNode<CommandSourceStack>) rebuild(command.build(), moduleName, active, unavailable);
}
@SuppressWarnings("unchecked")
private static @NotNull CommandNode<CommandSourceStack> rebuild(
@NotNull CommandNode<CommandSourceStack> node,
@NotNull String moduleName,
@NotNull BooleanSupplier active,
@NotNull ModuleUnavailableHandler unavailable
) {
// A redirect points at a node outside this rebuild, which would bypass the guard.
if (node.getRedirect() != null) {
throw new IllegalArgumentException("Module '" + moduleName + "' declared a redirect at '"
+ node.getName() + "'; module commands must not use redirects");
}
ArgumentBuilder<CommandSourceStack, ?> builder = node.createBuilder();
Command<CommandSourceStack> command = node.getCommand();
if (command != null) {
builder.executes(ctx -> {
if (active.getAsBoolean()) {
return command.run(ctx);
}
unavailable.handle(ctx.getSource(), moduleName);
return 0;
});
}
if (node instanceof ArgumentCommandNode<CommandSourceStack, ?> argumentNode
&& argumentNode.getCustomSuggestions() != null) {
SuggestionProvider<CommandSourceStack> suggestions = argumentNode.getCustomSuggestions();
RequiredArgumentBuilder<CommandSourceStack, ?> argument = (RequiredArgumentBuilder<CommandSourceStack, ?>) builder;
argument.suggests((ctx, suggestionsBuilder) -> active.getAsBoolean()
? suggestions.getSuggestions(ctx, suggestionsBuilder)
: suggestionsBuilder.buildFuture());
}
for (CommandNode<CommandSourceStack> child : node.getChildren()) {
builder.then(rebuild(child, moduleName, active, unavailable));
}
return builder.build();
}
}