Supports the ability for commands to be registered internally (#12520)

This commit is contained in:
Owen
2025-05-06 16:05:00 -04:00
committed by GitHub
parent c98cd65802
commit 42a2a6c2b5
12 changed files with 92 additions and 52 deletions

View File

@@ -15,5 +15,9 @@ public enum CommandRegistrationFlag {
* @deprecated This is the default behavior now. * @deprecated This is the default behavior now.
*/ */
@Deprecated(since = "1.21.4") @Deprecated(since = "1.21.4")
FLATTEN_ALIASES FLATTEN_ALIASES,
/**
* Prevents this command from being sent to the client.
*/
SERVER_ONLY
} }

View File

@@ -13,7 +13,7 @@
+ public CommandNode<net.minecraft.commands.CommandSourceStack> clientNode; // Paper - Brigadier API + public CommandNode<net.minecraft.commands.CommandSourceStack> clientNode; // Paper - Brigadier API
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> unwrappedCached = null; // Paper - Brigadier Command API + public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> unwrappedCached = null; // Paper - Brigadier Command API
+ public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> wrappedCached = null; // Paper - Brigadier Command API + public CommandNode<io.papermc.paper.command.brigadier.CommandSourceStack> wrappedCached = null; // Paper - Brigadier Command API
+ public io.papermc.paper.command.brigadier.PluginCommandMeta pluginCommandMeta; // Paper - Brigadier Command API + public io.papermc.paper.command.brigadier.APICommandMeta apiCommandMeta; // Paper - Brigadier Command API
+ // CraftBukkit start + // CraftBukkit start
+ public void removeCommand(String name) { + public void removeCommand(String name) {
+ this.children.remove(name); + this.children.remove(name);

View File

@@ -172,7 +172,7 @@
} }
return null; return null;
@@ -359,26 +_,120 @@ @@ -359,26 +_,121 @@
} }
public void sendCommands(ServerPlayer player) { public void sendCommands(ServerPlayer player) {
@@ -252,6 +252,7 @@
+ } + }
+ // Paper end - Brigadier API + // Paper end - Brigadier API
+ if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot + if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot
+ if (commandNode.wrappedCached != null && commandNode.wrappedCached.apiCommandMeta != null && commandNode.wrappedCached.apiCommandMeta.serverSideOnly()) continue; // Paper
if (commandNode.canUse(source)) { if (commandNode.canUse(source)) {
ArgumentBuilder<SharedSuggestionProvider, ?> argumentBuilder = (ArgumentBuilder) commandNode.createBuilder(); ArgumentBuilder<SharedSuggestionProvider, ?> argumentBuilder = (ArgumentBuilder) commandNode.createBuilder();
+ // Paper start + // Paper start

View File

@@ -1,12 +1,13 @@
--- a/net/minecraft/server/ReloadableServerResources.java --- a/net/minecraft/server/ReloadableServerResources.java
+++ b/net/minecraft/server/ReloadableServerResources.java +++ b/net/minecraft/server/ReloadableServerResources.java
@@ -38,7 +_,8 @@ @@ -38,7 +_,9 @@
this.fullRegistryHolder = new ReloadableServerRegistries.Holder(registryAccess.compositeAccess()); this.fullRegistryHolder = new ReloadableServerRegistries.Holder(registryAccess.compositeAccess());
this.postponedTags = postponedTags; this.postponedTags = postponedTags;
this.recipes = new RecipeManager(registries); this.recipes = new RecipeManager(registries);
- this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures)); - this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures));
+ this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration + this.commands = new Commands(commandSelection, CommandBuildContext.simple(registries, enabledFeatures), true); // Paper - Brigadier Command API - use modern alias registration
+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(registries, enabledFeatures)); // Paper - Brigadier Command API + io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setDispatcher(this.commands, CommandBuildContext.simple(registries, enabledFeatures)); // Paper - Brigadier Command API
+ io.papermc.paper.command.PaperCommands.registerCommands(); // Paper
this.advancements = new ServerAdvancementManager(registries); this.advancements = new ServerAdvancementManager(registries);
this.functionLibrary = new ServerFunctionLibrary(functionCompilationLevel, this.commands.getDispatcher()); this.functionLibrary = new ServerFunctionLibrary(functionCompilationLevel, this.commands.getDispatcher());
} }

View File

@@ -1,10 +1,15 @@
package io.papermc.paper.command; package io.papermc.paper.command;
import com.mojang.brigadier.tree.LiteralCommandNode;
import io.papermc.paper.command.brigadier.CommandRegistrationFlag;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier; import org.checkerframework.framework.qual.DefaultQualifier;
@@ -15,16 +20,31 @@ public final class PaperCommands {
} }
private static final Map<String, Command> COMMANDS = new HashMap<>(); private static final Map<String, Command> COMMANDS = new HashMap<>();
static {
public static void registerCommands(final MinecraftServer server) {
COMMANDS.put("paper", new PaperCommand("paper")); COMMANDS.put("paper", new PaperCommand("paper"));
COMMANDS.put("callback", new CallbackCommand("callback")); COMMANDS.put("callback", new CallbackCommand("callback"));
COMMANDS.put("mspt", new MSPTCommand("mspt")); COMMANDS.put("mspt", new MSPTCommand("mspt"));
}
public static void registerCommands(final MinecraftServer server) {
COMMANDS.forEach((s, command) -> { COMMANDS.forEach((s, command) -> {
server.server.getCommandMap().register(s, "Paper", command); server.server.getCommandMap().register(s, "Paper", command);
}); });
server.server.getCommandMap().register("bukkit", new PaperPluginsCommand()); server.server.getCommandMap().register("bukkit", new PaperPluginsCommand());
} }
public static void registerCommands() {
// Paper commands go here
}
private static void registerInternalCommand(final LiteralCommandNode<CommandSourceStack> node, final String description, final List<String> aliases, final Set<CommandRegistrationFlag> flags) {
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.registerWithFlagsInternal(
null,
"paper",
"Paper",
node,
description,
aliases,
flags
);
}
} }

View File

@@ -0,0 +1,31 @@
package io.papermc.paper.command.brigadier;
import io.papermc.paper.plugin.configuration.PluginMeta;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String description, List<String> aliases, @Nullable String helpCommandNamespace, boolean serverSideOnly) {
public APICommandMeta(final @Nullable PluginMeta pluginMeta, final @Nullable String description) {
this(pluginMeta, description, Collections.emptyList(), null, false);
}
public APICommandMeta {
aliases = List.copyOf(aliases);
}
@Nullable
public Plugin plugin() {
return this.pluginMeta == null ? null : Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
}
public APICommandMeta withAliases(List<String> registeredAliases) {
return new APICommandMeta(this.pluginMeta, this.description, List.copyOf(registeredAliases), this.helpCommandNamespace, this.serverSideOnly);
}
}

View File

@@ -35,8 +35,8 @@ public final class PaperBrigadier {
throw new IllegalArgumentException("Unsure how to wrap a " + node); throw new IllegalArgumentException("Unsure how to wrap a " + node);
} }
final PluginCommandMeta meta; final APICommandMeta meta;
if ((meta = node.pluginCommandMeta) == null) { if ((meta = node.apiCommandMeta) == null) {
return new VanillaCommandWrapper(node); return new VanillaCommandWrapper(node);
} }
CommandNode<CommandSourceStack> argumentCommandNode = node; CommandNode<CommandSourceStack> argumentCommandNode = node;
@@ -46,6 +46,12 @@ public final class PaperBrigadier {
Map<CommandNode<CommandSourceStack>, String> map = PaperCommands.INSTANCE.getDispatcherInternal().getSmartUsage(argumentCommandNode, DUMMY); Map<CommandNode<CommandSourceStack>, String> map = PaperCommands.INSTANCE.getDispatcherInternal().getSmartUsage(argumentCommandNode, DUMMY);
String usage = map.isEmpty() ? node.getUsageText() : node.getUsageText() + " " + String.join("\n" + node.getUsageText() + " ", map.values()); String usage = map.isEmpty() ? node.getUsageText() : node.getUsageText() + " " + String.join("\n" + node.getUsageText() + " ", map.values());
// Internal command
if (meta.pluginMeta() == null) {
return new VanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.helpCommandNamespace());
}
return new PluginVanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.plugin()); return new PluginVanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.plugin());
} }

View File

@@ -91,10 +91,13 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
@Override @Override
public @Unmodifiable Set<String> registerWithFlags(final PluginMeta pluginMeta, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) { public @Unmodifiable Set<String> registerWithFlags(final PluginMeta pluginMeta, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
final PluginCommandMeta meta = new PluginCommandMeta(pluginMeta, description); return registerWithFlagsInternal(pluginMeta, pluginMeta.getName().toLowerCase(Locale.ROOT), null, node, description, aliases, flags);
final String identifier = pluginMeta.getName().toLowerCase(Locale.ROOT); }
public @Unmodifiable Set<String> registerWithFlagsInternal(final @Nullable PluginMeta pluginMeta, final String namespace, final @Nullable String helpNamespaceOverride, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
final APICommandMeta meta = new APICommandMeta(pluginMeta, description, List.of(), helpNamespaceOverride, flags.contains(CommandRegistrationFlag.SERVER_ONLY));
final String literal = node.getLiteral(); final String literal = node.getLiteral();
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(identifier + ":" + literal, node); final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(namespace + ":" + literal, node);
final Set<String> registeredLabels = new HashSet<>(aliases.size() * 2 + 2); final Set<String> registeredLabels = new HashSet<>(aliases.size() * 2 + 2);
@@ -111,27 +114,27 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
if (this.registerCopy(alias, pluginLiteral, meta)) { if (this.registerCopy(alias, pluginLiteral, meta)) {
registeredAliases.add(alias); registeredAliases.add(alias);
} }
if (this.registerCopy(identifier + ":" + alias, pluginLiteral, meta)) { if (this.registerCopy(namespace + ":" + alias, pluginLiteral, meta)) {
registeredAliases.add(identifier + ":" + alias); registeredAliases.add(namespace + ":" + alias);
} }
} }
pluginLiteral.pluginCommandMeta = new PluginCommandMeta(pluginMeta, description, registeredAliases); pluginLiteral.apiCommandMeta = meta.withAliases(registeredAliases);
node.pluginCommandMeta = pluginLiteral.pluginCommandMeta; node.apiCommandMeta = pluginLiteral.apiCommandMeta;
registeredLabels.addAll(registeredAliases); registeredLabels.addAll(registeredAliases);
return registeredLabels.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(registeredLabels); return registeredLabels.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(registeredLabels);
} }
private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final PluginCommandMeta meta) { private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final APICommandMeta meta) {
final LiteralCommandNode<CommandSourceStack> node = PaperBrigadier.copyLiteral(aliasLiteral, redirectTo); final LiteralCommandNode<CommandSourceStack> node = PaperBrigadier.copyLiteral(aliasLiteral, redirectTo);
node.pluginCommandMeta = meta; node.apiCommandMeta = meta;
return this.registerIntoDispatcher(node, false); return this.registerIntoDispatcher(node, false);
} }
private boolean registerIntoDispatcher(final LiteralCommandNode<CommandSourceStack> node, boolean override) { private boolean registerIntoDispatcher(final LiteralCommandNode<CommandSourceStack> node, boolean override) {
final CommandNode<CommandSourceStack> existingChild = this.getDispatcher().getRoot().getChild(node.getLiteral()); final CommandNode<CommandSourceStack> existingChild = this.getDispatcher().getRoot().getChild(node.getLiteral());
if (existingChild != null && existingChild.pluginCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) { if (existingChild != null && existingChild.apiCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) {
override = true; // override vanilla commands override = true; // override vanilla commands
} }
if (existingChild == null || override) { // Avoid merging behavior. Maybe something to look into in the future if (existingChild == null || override) { // Avoid merging behavior. Maybe something to look into in the future

View File

@@ -1,26 +0,0 @@
package io.papermc.paper.command.brigadier;
import io.papermc.paper.plugin.configuration.PluginMeta;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public record PluginCommandMeta(PluginMeta pluginMeta, @Nullable String description, List<String> aliases) {
public PluginCommandMeta(final PluginMeta pluginMeta, final @Nullable String description) {
this(pluginMeta, description, Collections.emptyList());
}
public PluginCommandMeta {
aliases = List.copyOf(aliases);
}
public Plugin plugin() {
return Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
}
}

View File

@@ -17,7 +17,7 @@ public class PluginVanillaCommandWrapper extends VanillaCommandWrapper implement
private final List<String> aliases; private final List<String> aliases;
public PluginVanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, Plugin plugin) { public PluginVanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, Plugin plugin) {
super(name, description, usageMessage, aliases, vanillaCommand); super(name, description, usageMessage, aliases, vanillaCommand, null);
this.plugin = plugin; this.plugin = plugin;
this.aliases = aliases; this.aliases = aliases;
} }

View File

@@ -26,10 +26,12 @@ import org.bukkit.entity.minecart.CommandMinecart;
public class VanillaCommandWrapper extends BukkitCommand { // Paper public class VanillaCommandWrapper extends BukkitCommand { // Paper
public final CommandNode<CommandSourceStack> vanillaCommand; public final CommandNode<CommandSourceStack> vanillaCommand;
public final String helpCommandNamespace;
public VanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand) { public VanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, String helpCommandNamespace) {
super(name, description, usageMessage, aliases); super(name, description, usageMessage, aliases);
this.vanillaCommand = vanillaCommand; this.vanillaCommand = vanillaCommand;
this.helpCommandNamespace = helpCommandNamespace;
} }
Commands commands() { Commands commands() {
@@ -40,6 +42,7 @@ public class VanillaCommandWrapper extends BukkitCommand { // Paper
super(vanillaCommand.getName(), "A Mojang provided command.", vanillaCommand.getUsageText(), Collections.emptyList()); super(vanillaCommand.getName(), "A Mojang provided command.", vanillaCommand.getUsageText(), Collections.emptyList());
this.vanillaCommand = vanillaCommand; this.vanillaCommand = vanillaCommand;
this.setPermission(VanillaCommandWrapper.getPermission(vanillaCommand)); this.setPermission(VanillaCommandWrapper.getPermission(vanillaCommand));
this.helpCommandNamespace = "Minecraft";
} }
@Override @Override

View File

@@ -199,18 +199,15 @@ public class SimpleHelpMap implements HelpMap {
} }
private String getCommandPluginName(Command command) { private String getCommandPluginName(Command command) {
// Paper start - Move up
if (command instanceof PluginIdentifiableCommand) { if (command instanceof PluginIdentifiableCommand) {
return ((PluginIdentifiableCommand) command).getPlugin().getName(); return ((PluginIdentifiableCommand) command).getPlugin().getName();
} }
// Paper end if (command instanceof VanillaCommandWrapper wrapper) {
if (command instanceof VanillaCommandWrapper) { return wrapper.helpCommandNamespace;
return "Minecraft";
} }
if (command instanceof BukkitCommand) { if (command instanceof BukkitCommand) {
return "Bukkit"; return "Bukkit";
} }
// Paper - Move PluginIdentifiableCommand instanceof check to allow brig commands
return null; return null;
} }