Skip to content

Commit a275c4c

Browse files
Add questionable "prefix" entry compatibility
1 parent 6e6d489 commit a275c4c

3 files changed

Lines changed: 70 additions & 26 deletions

File tree

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

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
import java.lang.invoke.MethodHandle;
1414
import java.lang.invoke.MethodHandles;
1515
import java.lang.invoke.MethodType;
16+
import java.lang.reflect.InvocationHandler;
17+
import java.lang.reflect.Method;
18+
import java.lang.reflect.Proxy;
1619
import java.util.Collection;
20+
import java.util.Locale;
1721
import java.util.Map;
1822
import java.util.Set;
1923
import java.util.concurrent.ConcurrentHashMap;
@@ -34,15 +38,16 @@ public final class RuntimeCommandRegistrar {
3438
public record CommandRegistration(
3539
LiteralCommandNode<CommandSourceStack> node,
3640
Collection<String> aliases,
37-
@Nullable String description
41+
@Nullable String description,
42+
@Nullable String namespace
3843
) { }
3944

4045
private static JavaPlugin plugin;
4146

4247
private static Commands commandRegistrar;
4348
private static final Map<CommandRegistration, Set<String>> REGISTERED_COMMANDS = new ConcurrentHashMap<>();
44-
private static final Set<CommandRegistration> PENDING_REGISTRATION = ConcurrentHashMap.newKeySet();
45-
private static final Set<String> PENDING_UNREGISTRATION = ConcurrentHashMap.newKeySet();
49+
private static final Set<CommandRegistration> PENDING_REGISTRATIONS = ConcurrentHashMap.newKeySet();
50+
private static final Set<String> PENDING_UNREGISTRATIONS = ConcurrentHashMap.newKeySet();
4651

4752
private static @Nullable MethodHandle SET_VALID;
4853
private static @Nullable MethodHandle INVALIDATE;
@@ -56,13 +61,10 @@ public static void init(JavaPlugin plugin) {
5661
plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> {
5762
commandRegistrar = commands.registrar();
5863

59-
if (!REGISTERED_COMMANDS.isEmpty() || !PENDING_REGISTRATION.isEmpty()) {
64+
if (!REGISTERED_COMMANDS.isEmpty() || !PENDING_REGISTRATIONS.isEmpty()) {
6065
REGISTERED_COMMANDS.replaceAll((command, ignored) ->
6166
commandRegistrar.register(command.node, command.description, command.aliases));
62-
for (CommandRegistration command : PENDING_REGISTRATION) {
63-
REGISTERED_COMMANDS.put(command, commandRegistrar.register(command.node, command.description, command.aliases));
64-
}
65-
PENDING_REGISTRATION.clear();
67+
processRegistrationSet();
6668
return;
6769
}
6870

@@ -88,7 +90,7 @@ public static void init(JavaPlugin plugin) {
8890
* @see #processRegistrations()
8991
*/
9092
public static void register(CommandRegistration command) {
91-
PENDING_REGISTRATION.add(command);
93+
PENDING_REGISTRATIONS.add(command);
9294
}
9395

9496
/**
@@ -101,7 +103,7 @@ public static void processRegistrations() {
101103
return;
102104
}
103105

104-
if (!PENDING_UNREGISTRATION.isEmpty()) {
106+
if (!PENDING_UNREGISTRATIONS.isEmpty()) {
105107
processUnregistrations();
106108
}
107109

@@ -113,25 +115,64 @@ public static void processRegistrations() {
113115

114116
try {
115117
SET_VALID.invoke(commandRegistrar);
116-
PluginMeta pluginMeta = plugin.getPluginMeta();
117-
for (CommandRegistration command : PENDING_REGISTRATION) {
118-
REGISTERED_COMMANDS.put(command, commandRegistrar.register(pluginMeta, command.node, command.description, command.aliases));
119-
}
118+
processRegistrationSet();
120119
INVALIDATE.invoke(commandRegistrar);
121120
SYNC_COMMANDS.invoke(Bukkit.getServer());
122121
} catch (Throwable e) {
123122
throw Skript.exception(e);
124123
}
125124
}
126125

126+
private static void processRegistrationSet() {
127+
PluginMeta pluginMeta = plugin.getPluginMeta();
128+
for (CommandRegistration command : PENDING_REGISTRATIONS) {
129+
if (command.namespace == null) {
130+
REGISTERED_COMMANDS.put(command, commandRegistrar.register(pluginMeta, command.node, command.description, command.aliases));
131+
} else {
132+
TemporaryNamePluginMeta handler = new TemporaryNamePluginMeta(pluginMeta, command.namespace);
133+
PluginMeta meta = (PluginMeta) Proxy.newProxyInstance(pluginMeta.getClass().getClassLoader(),
134+
new Class<?>[]{PluginMeta.class}, handler);
135+
REGISTERED_COMMANDS.put(command, commandRegistrar.register(meta, command.node, command.description, command.aliases));
136+
handler.useAlternativeName = false;
137+
}
138+
}
139+
PENDING_REGISTRATIONS.clear();
140+
}
141+
142+
private static class TemporaryNamePluginMeta implements InvocationHandler {
143+
144+
final PluginMeta source;
145+
final String name;
146+
boolean useAlternativeName = true;
147+
148+
public TemporaryNamePluginMeta(PluginMeta source, String name) {
149+
this.source = source;
150+
this.name = name;
151+
}
152+
153+
@Override
154+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
155+
if (useAlternativeName) {
156+
String methodName = method.getName();
157+
if (methodName.equals("getName")) {
158+
return name;
159+
} else if (methodName.equals("namespace")) {
160+
return name.toLowerCase(Locale.ROOT);
161+
}
162+
}
163+
return method.invoke(source, args);
164+
}
165+
166+
}
167+
127168
/**
128169
* Adds the {@code command} to the unregistration queue.
129170
* To finalize unregistration, the queue must be processed using {@link #processUnregistrations()}.
130171
* @param command The command to unregister.
131172
* @see #processUnregistrations()
132173
*/
133174
public static void unregister(CommandRegistration command) {
134-
PENDING_UNREGISTRATION.addAll(REGISTERED_COMMANDS.remove(command));
175+
PENDING_UNREGISTRATIONS.addAll(REGISTERED_COMMANDS.remove(command));
135176
}
136177

137178
/**
@@ -145,7 +186,7 @@ public static void processUnregistrations() {
145186
}
146187

147188
if (useSafeReload) {
148-
PENDING_UNREGISTRATION.clear();
189+
PENDING_UNREGISTRATIONS.clear();
149190
Bukkit.reloadData();
150191
return;
151192
}
@@ -154,10 +195,10 @@ public static void processUnregistrations() {
154195
try {
155196
SET_VALID.invoke(commandRegistrar);
156197
var root = commandRegistrar.getDispatcher().getRoot();
157-
for (String command : PENDING_UNREGISTRATION) {
198+
for (String command : PENDING_UNREGISTRATIONS) {
158199
REMOVE_COMMAND.invoke(root, command);
159200
}
160-
PENDING_UNREGISTRATION.clear();
201+
PENDING_UNREGISTRATIONS.clear();
161202
INVALIDATE.invoke(commandRegistrar);
162203
SYNC_COMMANDS.invoke(Bukkit.getServer());
163204
} catch (Throwable e) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public boolean load() {
5959
Skript.error("A command must have a name.");
6060
return false;
6161
}
62-
command = new CommandRegistration(node, result.aliases(), result.description());
62+
command = new CommandRegistration(node, result.aliases(), result.description(), result.prefix());
6363
// TODO validate whether command already exists
6464

6565
RuntimeCommandRegistrar.register(command);

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public class SubCommandEntryData extends EntryData<Result> {
5656
public record Result(
5757
List<ArgumentBuilder<CommandSourceStack, ?>> arguments,
5858
Collection<String> aliases,
59-
@Nullable String description
59+
@Nullable String description,
60+
@Nullable String prefix
6061
) { }
6162

6263
private static final Predicate<CommandSender> TRUE_PREDICATE = ignored -> true;
@@ -82,6 +83,7 @@ protected List<String> getValue(String value) {
8283
}
8384
})
8485
.addEntry("description", null, true)
86+
.addEntry("prefix", null, true)
8587
.addEntry("permission", null, true)
8688
.addEntryData(new KeyValueEntryData<ExecutableBy>("executable by", null, true) {
8789
private final Pattern pattern = Pattern.compile("\\s*,\\s*|\\s+(and|or)\\s+");
@@ -110,7 +112,6 @@ protected ExecutableBy getValue(String value) {
110112
.addEntryData(new SubCommandEntryData("subcommand", true, true))
111113
// deprecated entries
112114
.addEntry("usage", null, true)
113-
.addEntry("prefix", null, true)
114115
.addEntry("permission message", null, true)
115116
.build();
116117

@@ -188,6 +189,12 @@ public SubCommandEntryData(String key, boolean optional, boolean multiple) {
188189
return null;
189190
}
190191

192+
String prefix = entryContainer.getOptional("prefix", String.class, false);
193+
if (!isRoot && prefix != null) {
194+
Skript.error("Only the root of a command may have a prefix.");
195+
return null;
196+
}
197+
191198
// command requirements
192199
Predicate<CommandSender> requires = TRUE_PREDICATE;
193200

@@ -255,10 +262,6 @@ public SubCommandEntryData(String key, boolean optional, boolean multiple) {
255262
ScriptWarning.printDeprecationWarning("The 'usage' entry has been deprecated for removal in a future release." +
256263
" Incorrect command usage is now handled by the client's command validator.");
257264
}
258-
if (entryContainer.hasEntry("prefix")) {
259-
ScriptWarning.printDeprecationWarning("The 'prefix' entry has been deprecated for removal in a future release." +
260-
" It is no longer possible to modify the prefix (namespace) of a command.");
261-
}
262265
if (entryContainer.hasEntry("permission message")) {
263266
ScriptWarning.printDeprecationWarning("The 'permission message' entry has been deprecated for removal in a future release." +
264267
" Commands that a player does not have permission to execute are no longer sent to their client.");
@@ -319,7 +322,7 @@ public SubCommandEntryData(String key, boolean optional, boolean multiple) {
319322
parsingData.popArguments();
320323

321324
//noinspection unchecked
322-
return new Result(result, aliases, description);
325+
return new Result(result, aliases, description, prefix);
323326
}
324327

325328
@Override

0 commit comments

Comments
 (0)