Brigadier based command API

== AT ==
public net.minecraft.commands.arguments.blocks.BlockInput tag
public net.minecraft.commands.arguments.DimensionArgument ERROR_INVALID_VALUE
public net.minecraft.server.ReloadableServerResources registryLookup
public net.minecraft.server.ReloadableServerResources

Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Marc Baloup <marc.baloup@laposte.net>
This commit is contained in:
Owen1212055
2022-08-01 22:50:34 -04:00
parent aabe9f5264
commit 977543c545
37 changed files with 2324 additions and 304 deletions

View File

@@ -275,11 +275,11 @@ public final class CraftServer implements Server {
private final Logger logger = Logger.getLogger("Minecraft");
private final ServicesManager servicesManager = new SimpleServicesManager();
private final CraftScheduler scheduler = new CraftScheduler();
private final CraftCommandMap commandMap = new CraftCommandMap(this);
private final CraftCommandMap commandMap; // Paper - Move down
private final SimpleHelpMap helpMap = new SimpleHelpMap(this);
private final StandardMessenger messenger = new StandardMessenger();
private final SimplePluginManager pluginManager = new SimplePluginManager(this, commandMap);
public final io.papermc.paper.plugin.manager.PaperPluginManagerImpl paperPluginManager = new io.papermc.paper.plugin.manager.PaperPluginManagerImpl(this, this.commandMap, pluginManager); {this.pluginManager.paperPluginManager = this.paperPluginManager;} // Paper
private final SimplePluginManager pluginManager; // Paper - Move down
public final io.papermc.paper.plugin.manager.PaperPluginManagerImpl paperPluginManager; // Paper
private final StructureManager structureManager;
protected final DedicatedServer console;
protected final DedicatedPlayerList playerList;
@@ -419,6 +419,12 @@ public final class CraftServer implements Server {
this.serverLinks = new CraftServerLinks(console);
Bukkit.setServer(this);
// Paper start
this.commandMap = new CraftCommandMap(this);
this.pluginManager = new SimplePluginManager(this, commandMap);
this.paperPluginManager = new io.papermc.paper.plugin.manager.PaperPluginManagerImpl(this, this.commandMap, pluginManager);
this.pluginManager.paperPluginManager = this.paperPluginManager;
// Paper end
CraftRegistry.setMinecraftRegistry(console.registryAccess());
@@ -617,48 +623,11 @@ public final class CraftServer implements Server {
}
private void setVanillaCommands(boolean first) { // Spigot
Commands dispatcher = this.console.vanillaCommandDispatcher;
// Build a list of all Vanilla commands and create wrappers
for (CommandNode<CommandSourceStack> cmd : dispatcher.getDispatcher().getRoot().getChildren()) {
// Spigot start
VanillaCommandWrapper wrapper = new VanillaCommandWrapper(dispatcher, cmd);
if (org.spigotmc.SpigotConfig.replaceCommands.contains( wrapper.getName() ) ) {
if (first) {
this.commandMap.register("minecraft", wrapper);
}
} else if (!first) {
this.commandMap.register("minecraft", wrapper);
}
// Spigot end
}
// Paper - Replace implementation
}
public void syncCommands() {
// Clear existing commands
Commands dispatcher = this.console.resources.managers().commands = new Commands();
// Register all commands, vanilla ones will be using the old dispatcher references
for (Map.Entry<String, Command> entry : this.commandMap.getKnownCommands().entrySet()) {
String label = entry.getKey();
Command command = entry.getValue();
if (command instanceof VanillaCommandWrapper) {
LiteralCommandNode<CommandSourceStack> node = (LiteralCommandNode<CommandSourceStack>) ((VanillaCommandWrapper) command).vanillaCommand;
if (!node.getLiteral().equals(label)) {
LiteralCommandNode<CommandSourceStack> clone = new LiteralCommandNode(label, node.getCommand(), node.getRequirement(), node.getRedirect(), node.getRedirectModifier(), node.isFork());
for (CommandNode<CommandSourceStack> child : node.getChildren()) {
clone.addChild(child);
}
node = clone;
}
dispatcher.getDispatcher().getRoot().addChild(node);
} else {
new BukkitCommandWrapper(this, entry.getValue()).register(dispatcher.getDispatcher(), label);
}
}
Commands dispatcher = this.getHandle().getServer().getCommands(); // Paper - We now register directly to the dispatcher.
// Refresh commands
for (ServerPlayer player : this.getHandle().players) {
@@ -1045,17 +1014,31 @@ public final class CraftServer implements Server {
return true;
}
// Spigot start
if (!org.spigotmc.SpigotConfig.unknownCommandMessage.isEmpty()) {
// Paper start
org.bukkit.event.command.UnknownCommandEvent event = new org.bukkit.event.command.UnknownCommandEvent(sender, commandLine, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.unknownCommandMessage));
this.getPluginManager().callEvent(event);
if (event.message() != null) {
sender.sendMessage(event.message());
}
// Paper end
return this.dispatchCommand(VanillaCommandWrapper.getListener(sender), commandLine);
}
public boolean dispatchCommand(CommandSourceStack sourceStack, String commandLine) {
net.minecraft.commands.Commands commands = this.getHandle().getServer().getCommands();
com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher = commands.getDispatcher();
com.mojang.brigadier.ParseResults<CommandSourceStack> results = dispatcher.parse(commandLine, sourceStack);
CommandSender sender = sourceStack.getBukkitSender();
String[] args = org.apache.commons.lang3.StringUtils.split(commandLine, ' '); // Paper - fix adjacent spaces (from console/plugins) causing empty array elements
Command target = this.commandMap.getCommand(args[0].toLowerCase(java.util.Locale.ENGLISH));
try {
commands.performCommand(results, commandLine, commandLine, true);
} catch (CommandException ex) {
this.pluginManager.callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper
//target.timings.stopTiming(); // Spigot // Paper
throw ex;
} catch (Throwable ex) {
//target.timings.stopTiming(); // Spigot // Paper
String msg = "Unhandled exception executing '" + commandLine + "' in " + target;
this.pluginManager.callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper
throw new CommandException(msg, ex);
}
// Spigot end
// Paper end
return false;
}
@@ -1064,7 +1047,7 @@ public final class CraftServer implements Server {
public void reload() {
// Paper start - lifecycle events
if (io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.blocksPluginReloading()) {
throw new IllegalStateException("A lifecycle event handler has been registered which makes reloading plugins not possible");
throw new IllegalStateException(org.bukkit.command.defaults.ReloadCommand.RELOADING_DISABLED_MESSAGE);
}
// Paper end - lifecycle events
org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload
@@ -1119,8 +1102,9 @@ public final class CraftServer implements Server {
}
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
this.commandMap.clearCommands(); // Paper - Move command reloading up
this.pluginManager.clearPlugins();
this.commandMap.clearCommands();
// Paper - move up
// Paper start
for (Plugin plugin : pluginClone) {
entityMetadata.removeAll(plugin);
@@ -1160,6 +1144,12 @@ public final class CraftServer implements Server {
this.enablePlugins(PluginLoadOrder.STARTUP);
this.enablePlugins(PluginLoadOrder.POSTWORLD);
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
// Paper start - brigadier command API
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.setValid(); // to clear invalid state for event fire below
io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS, io.papermc.paper.command.brigadier.PaperCommands.INSTANCE, org.bukkit.plugin.Plugin.class, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD); // call commands event for regular plugins
this.helpMap.initializeCommands();
this.syncCommands(); // Refresh commands after event
// Paper end - brigadier command API
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
}

View File

@@ -20,6 +20,7 @@ import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftServer;
@Deprecated(forRemoval = true) // Paper - Don't use
public class BukkitCommandWrapper implements com.mojang.brigadier.Command<CommandSourceStack>, Predicate<CommandSourceStack>, SuggestionProvider<CommandSourceStack>, com.destroystokyo.paper.brigadier.BukkitBrigadierCommand<CommandSourceStack> { // Paper
private final CraftServer server;

View File

@@ -8,7 +8,7 @@ import org.bukkit.command.SimpleCommandMap;
public class CraftCommandMap extends SimpleCommandMap {
public CraftCommandMap(Server server) {
super(server);
super(server, io.papermc.paper.command.brigadier.bukkit.BukkitBrigForwardingMap.INSTANCE);
}
public Map<String, Command> getKnownCommands() {

View File

@@ -24,14 +24,26 @@ import org.bukkit.craftbukkit.entity.CraftMinecartCommand;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.minecart.CommandMinecart;
public final class VanillaCommandWrapper extends BukkitCommand {
public class VanillaCommandWrapper extends BukkitCommand { // Paper
private final Commands dispatcher;
//private final Commands dispatcher; // Paper
public final CommandNode<CommandSourceStack> vanillaCommand;
// Paper start
public VanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand) {
super(name, description, usageMessage, aliases);
//this.dispatcher = dispatcher; // Paper
this.vanillaCommand = vanillaCommand;
}
Commands commands() {
return net.minecraft.server.MinecraftServer.getServer().getCommands();
}
// Paper end
public VanillaCommandWrapper(Commands dispatcher, CommandNode<CommandSourceStack> vanillaCommand) {
super(vanillaCommand.getName(), "A Mojang provided command.", vanillaCommand.getUsageText(), Collections.EMPTY_LIST);
this.dispatcher = dispatcher;
// this.dispatcher = dispatcher; // Paper
this.vanillaCommand = vanillaCommand;
this.setPermission(VanillaCommandWrapper.getPermission(vanillaCommand));
}
@@ -41,7 +53,7 @@ public final class VanillaCommandWrapper extends BukkitCommand {
if (!this.testPermission(sender)) return true;
CommandSourceStack icommandlistener = VanillaCommandWrapper.getListener(sender);
this.dispatcher.performPrefixedCommand(icommandlistener, this.toDispatcher(args, this.getName()), this.toDispatcher(args, commandLabel));
this.commands().performPrefixedCommand(icommandlistener, this.toDispatcher(args, this.getName()), this.toDispatcher(args, commandLabel)); // Paper
return true;
}
@@ -52,10 +64,10 @@ public final class VanillaCommandWrapper extends BukkitCommand {
Preconditions.checkArgument(alias != null, "Alias cannot be null");
CommandSourceStack icommandlistener = VanillaCommandWrapper.getListener(sender);
ParseResults<CommandSourceStack> parsed = this.dispatcher.getDispatcher().parse(this.toDispatcher(args, this.getName()), icommandlistener);
ParseResults<CommandSourceStack> parsed = this.commands().getDispatcher().parse(this.toDispatcher(args, this.getName()), icommandlistener); // Paper
List<String> results = new ArrayList<>();
this.dispatcher.getDispatcher().getCompletionSuggestions(parsed).thenAccept((suggestions) -> {
this.commands().getDispatcher().getCompletionSuggestions(parsed).thenAccept((suggestions) -> { // Paper
suggestions.getList().forEach((s) -> results.add(s.getText()));
});
@@ -116,4 +128,15 @@ public final class VanillaCommandWrapper extends BukkitCommand {
private String toDispatcher(String[] args, String name) {
return name + ((args.length > 0) ? " " + Joiner.on(' ').join(args) : "");
}
// Paper start
@Override
public boolean canBeOverriden() {
return true;
}
@Override
public boolean isRegistered() {
return true;
}
// Paper end
}

View File

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

View File

@@ -53,7 +53,13 @@ public final class CraftCriteria implements Criteria {
return RenderType.values()[this.criteria.getDefaultRenderType().ordinal()];
}
static CraftCriteria getFromNMS(Objective objective) {
// Paper start
public static CraftCriteria getFromNMS(ObjectiveCriteria criteria) {
return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(criteria.getName()), () -> new CraftCriteria(criteria));
}
// Paper end
public static CraftCriteria getFromNMS(Objective objective) {
return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper
}