Skip to content

Commit 868875b

Browse files
Improve registered command organization
1 parent 014cb21 commit 868875b

4 files changed

Lines changed: 73 additions & 43 deletions

File tree

src/main/java/org/skriptlang/skript/bukkit/command/CommandModule.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import org.skriptlang.skript.addon.AddonModule;
55
import org.skriptlang.skript.addon.HierarchicalAddonModule;
66
import org.skriptlang.skript.addon.SkriptAddon;
7-
import org.skriptlang.skript.bukkit.command.brigadier.RuntimeCommandRegistrar;
7+
import org.skriptlang.skript.bukkit.command.brigadier.SkriptCommandRegistrar;
88
import org.skriptlang.skript.bukkit.command.elements.effects.EffCancelCooldown;
99
import org.skriptlang.skript.bukkit.command.elements.expressions.ExprArgument;
1010
import org.skriptlang.skript.bukkit.command.elements.expressions.ExprCmdCooldownInfo;
@@ -18,7 +18,7 @@ public CommandModule(AddonModule parentModule) {
1818

1919
@Override
2020
protected void loadSelf(SkriptAddon addon) {
21-
RuntimeCommandRegistrar.init(Skript.getInstance());
21+
SkriptCommandRegistrar.init(Skript.getInstance());
2222

2323
register(addon,
2424
EffCancelCooldown::register,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.skriptlang.skript.bukkit.command.brigadier;
2+
3+
import com.mojang.brigadier.tree.LiteralCommandNode;
4+
import io.papermc.paper.command.brigadier.CommandSourceStack;
5+
import org.jetbrains.annotations.Nullable;
6+
import org.skriptlang.skript.lang.script.Script;
7+
8+
import java.util.Collection;
9+
10+
/**
11+
* @param script The script this command is defined in.
12+
* @param node The command node providing functionality for this command.
13+
* @param aliases Aliases used to reference the command. Can be empty.
14+
* @param description String describing the command.
15+
* @param namespace An alternative namespace the command is registered under.
16+
* If null, this command is registered under the default namespace (typically {@code skript}).
17+
*/
18+
public record SkriptBrigadierCommand(
19+
Script script,
20+
LiteralCommandNode<CommandSourceStack> node,
21+
Collection<String> aliases,
22+
@Nullable String description,
23+
@Nullable String namespace
24+
) { }

src/main/java/org/skriptlang/skript/bukkit/command/brigadier/RuntimeCommandRegistrar.java renamed to src/main/java/org/skriptlang/skript/bukkit/command/brigadier/SkriptCommandRegistrar.java

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.skriptlang.skript.bukkit.command.brigadier;
22

33
import ch.njol.skript.Skript;
4-
import com.mojang.brigadier.tree.LiteralCommandNode;
5-
import io.papermc.paper.command.brigadier.CommandSourceStack;
64
import io.papermc.paper.command.brigadier.Commands;
75
import io.papermc.paper.plugin.configuration.PluginMeta;
86
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
@@ -16,36 +14,23 @@
1614
import java.lang.reflect.InvocationHandler;
1715
import java.lang.reflect.Method;
1816
import java.lang.reflect.Proxy;
19-
import java.util.Collection;
2017
import java.util.Map;
2118
import java.util.Set;
2219
import java.util.concurrent.ConcurrentHashMap;
20+
import java.util.stream.Stream;
2321

2422
/**
2523
* Utility class for registering Brigadier commands at runtime through reflection.
2624
* This avoids a full reload via {@link Bukkit#reloadData()}.
2725
* However, that approach will be used if the reflection-based approach fails to load.
2826
*/
29-
public final class RuntimeCommandRegistrar {
30-
31-
/**
32-
*
33-
* @param node The command node to register.
34-
* @param aliases Aliases used to reference the command. Can be empty.
35-
* @param description String describing the command.
36-
*/
37-
public record CommandRegistration(
38-
LiteralCommandNode<CommandSourceStack> node,
39-
Collection<String> aliases,
40-
@Nullable String description,
41-
@Nullable String namespace
42-
) { }
27+
public final class SkriptCommandRegistrar {
4328

4429
private static JavaPlugin plugin;
4530

4631
private static Commands commandRegistrar;
47-
private static final Map<CommandRegistration, Set<String>> REGISTERED_COMMANDS = new ConcurrentHashMap<>();
48-
private static final Set<CommandRegistration> PENDING_REGISTRATIONS = ConcurrentHashMap.newKeySet();
32+
private static final Map<SkriptBrigadierCommand, Set<String>> REGISTERED_COMMANDS = new ConcurrentHashMap<>();
33+
private static final Set<SkriptBrigadierCommand> PENDING_REGISTRATIONS = ConcurrentHashMap.newKeySet();
4934
private static final Set<String> PENDING_UNREGISTRATIONS = ConcurrentHashMap.newKeySet();
5035

5136
private static @Nullable MethodHandle SET_VALID;
@@ -56,13 +41,13 @@ public record CommandRegistration(
5641
private static boolean useSafeReload;
5742

5843
public static void init(JavaPlugin plugin) {
59-
RuntimeCommandRegistrar.plugin = plugin;
44+
SkriptCommandRegistrar.plugin = plugin;
6045
plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
6146
commandRegistrar = commands.registrar();
6247

6348
if (!REGISTERED_COMMANDS.isEmpty() || !PENDING_REGISTRATIONS.isEmpty()) {
6449
REGISTERED_COMMANDS.replaceAll((command, ignored) ->
65-
commandRegistrar.register(command.node, command.description, command.aliases));
50+
commandRegistrar.register(command.node(), command.description(), command.aliases()));
6651
processRegistrationSet();
6752
return;
6853
}
@@ -88,17 +73,17 @@ public static void init(JavaPlugin plugin) {
8873
* @param command The command to register.
8974
* @see #processRegistrations()
9075
*/
91-
public static void register(CommandRegistration command) {
76+
public static void register(SkriptBrigadierCommand command) {
9277
PENDING_REGISTRATIONS.add(command);
9378
}
9479

9580
/**
9681
* Processes all pending registrations, synchronizing them with the server's command dispatcher.
97-
* @see #register(CommandRegistration)
82+
* @see #register(SkriptBrigadierCommand)
9883
*/
9984
public static void processRegistrations() {
10085
if (!Bukkit.isPrimaryThread()) {
101-
Bukkit.getScheduler().runTask(plugin, RuntimeCommandRegistrar::processRegistrations);
86+
Bukkit.getScheduler().runTask(plugin, SkriptCommandRegistrar::processRegistrations);
10287
return;
10388
}
10489

@@ -124,14 +109,14 @@ public static void processRegistrations() {
124109

125110
private static void processRegistrationSet() {
126111
PluginMeta pluginMeta = plugin.getPluginMeta();
127-
for (CommandRegistration command : PENDING_REGISTRATIONS) {
128-
if (command.namespace == null) {
129-
REGISTERED_COMMANDS.put(command, commandRegistrar.register(pluginMeta, command.node, command.description, command.aliases));
112+
for (SkriptBrigadierCommand command : PENDING_REGISTRATIONS) {
113+
if (command.namespace() == null) {
114+
REGISTERED_COMMANDS.put(command, commandRegistrar.register(pluginMeta, command.node(), command.description(), command.aliases()));
130115
} else {
131-
TemporaryNamePluginMeta handler = new TemporaryNamePluginMeta(pluginMeta, command.namespace);
116+
TemporaryNamePluginMeta handler = new TemporaryNamePluginMeta(pluginMeta, command.namespace());
132117
PluginMeta meta = (PluginMeta) Proxy.newProxyInstance(pluginMeta.getClass().getClassLoader(),
133118
new Class<?>[]{PluginMeta.class}, handler);
134-
REGISTERED_COMMANDS.put(command, commandRegistrar.register(meta, command.node, command.description, command.aliases));
119+
REGISTERED_COMMANDS.put(command, commandRegistrar.register(meta, command.node(), command.description(), command.aliases()));
135120
handler.useAlternativeName = false;
136121
}
137122
}
@@ -168,17 +153,17 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
168153
* @param command The command to unregister.
169154
* @see #processUnregistrations()
170155
*/
171-
public static void unregister(CommandRegistration command) {
156+
public static void unregister(SkriptBrigadierCommand command) {
172157
PENDING_UNREGISTRATIONS.addAll(REGISTERED_COMMANDS.remove(command));
173158
}
174159

175160
/**
176161
* Processes all pending unregistrations, synchronizing them with the server's command dispatcher.
177-
* @see #unregister(CommandRegistration)
162+
* @see #unregister(SkriptBrigadierCommand)
178163
*/
179164
public static void processUnregistrations() {
180165
if (!Bukkit.isPrimaryThread()) {
181-
Bukkit.getScheduler().runTask(plugin, RuntimeCommandRegistrar::processUnregistrations);
166+
Bukkit.getScheduler().runTask(plugin, SkriptCommandRegistrar::processUnregistrations);
182167
return;
183168
}
184169

@@ -203,4 +188,16 @@ public static void processUnregistrations() {
203188
}
204189
}
205190

191+
/**
192+
* Obtains a script command by its name.
193+
* @param command The name of the command.
194+
* @return The script command named {@code command}, or null if no script command with that name exists.
195+
*/
196+
public static @Nullable SkriptBrigadierCommand getCommand(String command) {
197+
return Stream.concat(PENDING_REGISTRATIONS.stream(), REGISTERED_COMMANDS.keySet().stream())
198+
.filter(registration -> registration.node().getLiteral().equals(command))
199+
.findFirst()
200+
.orElse(null);
201+
}
202+
206203
}

src/main/java/org/skriptlang/skript/bukkit/command/elements/structures/StructCommand.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
import org.bukkit.event.Event;
1111
import org.jetbrains.annotations.Nullable;
1212
import org.skriptlang.skript.addon.SkriptAddon;
13-
import org.skriptlang.skript.bukkit.command.brigadier.RuntimeCommandRegistrar;
14-
import org.skriptlang.skript.bukkit.command.brigadier.RuntimeCommandRegistrar.CommandRegistration;
13+
import org.skriptlang.skript.bukkit.command.brigadier.SkriptCommandRegistrar;
14+
import org.skriptlang.skript.bukkit.command.brigadier.SkriptBrigadierCommand;
1515
import org.skriptlang.skript.bukkit.command.brigadier.ScriptCommandEvent;
1616
import org.skriptlang.skript.bukkit.command.elements.structures.util.SubCommandEntryData;
1717
import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue;
@@ -41,7 +41,7 @@ public static void register(SkriptAddon addon, SyntaxRegistry syntaxRegistry) {
4141
private static final AtomicBoolean SYNC_COMMANDS = new AtomicBoolean();
4242

4343
private SectionNode rootNode;
44-
private CommandRegistration command;
44+
private SkriptBrigadierCommand command;
4545

4646
@Override
4747
public boolean init(Literal<?>[] args, int matchedPattern, ParseResult parseResult, EntryContainer entryContainer) {
@@ -51,6 +51,7 @@ public boolean init(Literal<?>[] args, int matchedPattern, ParseResult parseResu
5151

5252
@Override
5353
public boolean load() {
54+
// parsing
5455
var result = ROOT_ENTRY_DATA.getValue(rootNode);
5556
if (result == null) { // parsing failed, entry will have emitted a specific error message
5657
return false;
@@ -59,10 +60,18 @@ public boolean load() {
5960
Skript.error("A command must have a name.");
6061
return false;
6162
}
62-
command = new CommandRegistration(node, result.aliases(), result.description(), result.prefix());
63-
// TODO validate whether command already exists
6463

65-
RuntimeCommandRegistrar.register(command);
64+
// validation
65+
SkriptBrigadierCommand existing = SkriptCommandRegistrar.getCommand(node.getLiteral());
66+
if (existing != null) {
67+
Skript.error("A command with the name /" + node.getLiteral() + " is already defined in the script '" +
68+
existing.script().nameAndPath() + ".sk'");
69+
return false;
70+
}
71+
72+
// registration
73+
command = new SkriptBrigadierCommand(getParser().getCurrentScript(), node, result.aliases(), result.description(), result.prefix());
74+
SkriptCommandRegistrar.register(command);
6675
SYNC_COMMANDS.set(true);
6776

6877
return true;
@@ -71,21 +80,21 @@ public boolean load() {
7180
@Override
7281
public boolean postLoad() {
7382
if (SYNC_COMMANDS.compareAndSet(true, false)) {
74-
RuntimeCommandRegistrar.processRegistrations();
83+
SkriptCommandRegistrar.processRegistrations();
7584
}
7685
return true;
7786
}
7887

7988
@Override
8089
public void unload() {
81-
RuntimeCommandRegistrar.unregister(command);
90+
SkriptCommandRegistrar.unregister(command);
8291
SYNC_COMMANDS.set(true);
8392
}
8493

8594
@Override
8695
public void postUnload() {
8796
if (SYNC_COMMANDS.compareAndSet(true, false)) {
88-
RuntimeCommandRegistrar.processUnregistrations();
97+
SkriptCommandRegistrar.processUnregistrations();
8998
}
9099
}
91100

0 commit comments

Comments
 (0)