Brigadier Command Support (#8235)

Adds the ability for plugins to register their own brigadier commands 

---------

Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Co-authored-by: Bjarne Koll <lynxplay101@gmail.com>
This commit is contained in:
Owen 2024-05-11 16:30:30 -04:00 committed by GitHub
parent 447f9a1e16
commit b98d20a8ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 5195 additions and 515 deletions

View file

@ -1,36 +0,0 @@
plugins {
`java-library`
`maven-publish`
}
java {
withSourcesJar()
withJavadocJar()
}
dependencies {
implementation(project(":paper-api"))
api("com.mojang:brigadier:1.0.18")
compileOnly("it.unimi.dsi:fastutil:8.5.6")
compileOnly("org.jetbrains:annotations:23.0.0")
testImplementation("junit:junit:4.13.2")
testImplementation("org.hamcrest:hamcrest-library:1.3")
testImplementation("org.ow2.asm:asm-tree:9.7")
}
configure<PublishingExtension> {
publications.create<MavenPublication>("maven") {
from(components["java"])
}
}
val scanJar = tasks.register("scanJarForBadCalls", io.papermc.paperweight.tasks.ScanJarForBadCalls::class) {
badAnnotations.add("Lio/papermc/paper/annotation/DoNotUse;")
jarToScan.set(tasks.jar.flatMap { it.archiveFile })
classpath.from(configurations.compileClasspath)
}
tasks.check {
dependsOn(scanJar)
}

View file

@ -1,14 +0,0 @@
package com.destroystokyo.paper.brigadier;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import java.util.function.Predicate;
/**
* Brigadier {@link Command}, {@link SuggestionProvider}, and permission checker for Bukkit {@link Command}s.
*
* @param <S> command source type
*/
public interface BukkitBrigadierCommand <S extends BukkitBrigadierCommandSource> extends Command<S>, Predicate<S>, SuggestionProvider<S> {
}

View file

@ -1,21 +0,0 @@
package com.destroystokyo.paper.brigadier;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.Nullable;
public interface BukkitBrigadierCommandSource {
@Nullable
Entity getBukkitEntity();
@Nullable
World getBukkitWorld();
@Nullable
Location getBukkitLocation();
CommandSender getBukkitSender();
}

View file

@ -1,72 +0,0 @@
package com.destroystokyo.paper.event.brigadier;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import com.mojang.brigadier.tree.RootCommandNode;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Fired any time a Brigadier RootCommandNode is generated for a player to inform the client of commands.
* You may manipulate this CommandNode to change what the client sees.
*
* <p>This event may fire on login, world change, and permission rebuilds, by plugin request, and potentially future means.</p>
*
* <p>This event will fire before {@link org.bukkit.event.player.PlayerCommandSendEvent}, so no filtering has been done by
* other plugins yet.</p>
*
* <p>WARNING: This event will potentially (and most likely) fire twice! Once for Async, and once again for Sync.
* It is important that you check event.isAsynchronous() and event.hasFiredAsync() to ensure you only act once.
* If for some reason we are unable to send this asynchronously in the future, only the sync method will fire.</p>
*
* <p>Your logic should look like this:
* {@code if (event.isAsynchronous() || !event.hasFiredAsync()) { // do stuff }}</p>
*
* <p>If your logic is not safe to run asynchronously, only react to the synchronous version.</p>
*
* <p>This is a draft/experimental API and is subject to change.</p>
*/
@ApiStatus.Experimental
public class AsyncPlayerSendCommandsEvent <S extends BukkitBrigadierCommandSource> extends PlayerEvent {
private static final HandlerList handlers = new HandlerList();
private final RootCommandNode<S> node;
private final boolean hasFiredAsync;
public AsyncPlayerSendCommandsEvent(Player player, RootCommandNode<S> node, boolean hasFiredAsync) {
super(player, !Bukkit.isPrimaryThread());
this.node = node;
this.hasFiredAsync = hasFiredAsync;
}
/**
* Gets the full Root Command Node being sent to the client, which is mutable.
*
* @return the root command node
*/
public RootCommandNode<S> getCommandNode() {
return node;
}
/**
* Gets if this event has already fired asynchronously.
*
* @return whether this event has already fired asynchronously
*/
public boolean hasFiredAsync() {
return hasFiredAsync;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,84 +0,0 @@
package com.destroystokyo.paper.event.brigadier;
import com.mojang.brigadier.suggestion.Suggestions;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.NotNull;
/**
* Called when sending {@link Suggestions} to the client. Will be called asynchronously if a plugin
* marks the {@link com.destroystokyo.paper.event.server.AsyncTabCompleteEvent} event handled asynchronously,
* otherwise called synchronously.
*/
public class AsyncPlayerSendSuggestionsEvent extends PlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
private Suggestions suggestions;
private final String buffer;
public AsyncPlayerSendSuggestionsEvent(Player player, Suggestions suggestions, String buffer) {
super(player, !Bukkit.isPrimaryThread());
this.suggestions = suggestions;
this.buffer = buffer;
}
/**
* Gets the input buffer sent to request these suggestions.
*
* @return the input buffer
*/
public String getBuffer() {
return buffer;
}
/**
* Gets the suggestions to be sent to client.
*
* @return the suggestions
*/
public Suggestions getSuggestions() {
return suggestions;
}
/**
* Sets the suggestions to be sent to client.
*
* @param suggestions suggestions
*/
public void setSuggestions(Suggestions suggestions) {
this.suggestions = suggestions;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isCancelled() {
return this.cancelled;
}
/**
* Cancels sending suggestions to the client.
* {@inheritDoc}
*/
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,168 +0,0 @@
package com.destroystokyo.paper.event.brigadier;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommand;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import org.bukkit.command.Command;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.server.ServerEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Fired anytime the server synchronizes Bukkit commands to Brigadier.
*
* <p>Allows a plugin to control the command node structure for its commands.
* This is done at Plugin Enable time after commands have been registered, but may also
* run at a later point in the server lifetime due to plugins, a server reload, etc.</p>
*
* <p>This is a draft/experimental API and is subject to change.</p>
*/
@ApiStatus.Experimental
public class CommandRegisteredEvent<S extends BukkitBrigadierCommandSource> extends ServerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final String commandLabel;
private final Command command;
private final BukkitBrigadierCommand<S> brigadierCommand;
private final RootCommandNode<S> root;
private final ArgumentCommandNode<S, String> defaultArgs;
private LiteralCommandNode<S> literal;
private boolean rawCommand = false;
private boolean cancelled = false;
public CommandRegisteredEvent(String commandLabel, BukkitBrigadierCommand<S> brigadierCommand, Command command, RootCommandNode<S> root, LiteralCommandNode<S> literal, ArgumentCommandNode<S, String> defaultArgs) {
this.commandLabel = commandLabel;
this.brigadierCommand = brigadierCommand;
this.command = command;
this.root = root;
this.literal = literal;
this.defaultArgs = defaultArgs;
}
/**
* Gets the command label of the {@link Command} being registered.
*
* @return the command label
*/
public String getCommandLabel() {
return this.commandLabel;
}
/**
* Gets the {@link BukkitBrigadierCommand} for the {@link Command} being registered. This can be used
* as the {@link com.mojang.brigadier.Command command executor} or
* {@link com.mojang.brigadier.suggestion.SuggestionProvider} of a {@link com.mojang.brigadier.tree.CommandNode}
* to delegate to the {@link Command} being registered.
*
* @return the {@link BukkitBrigadierCommand}
*/
public BukkitBrigadierCommand<S> getBrigadierCommand() {
return this.brigadierCommand;
}
/**
* Gets the {@link Command} being registered.
*
* @return the {@link Command}
*/
public Command getCommand() {
return this.command;
}
/**
* Gets the {@link RootCommandNode} which is being registered to.
*
* @return the {@link RootCommandNode}
*/
public RootCommandNode<S> getRoot() {
return this.root;
}
/**
* Gets the Bukkit APIs default arguments node (greedy string), for if
* you wish to reuse it.
*
* @return default arguments node
*/
public ArgumentCommandNode<S, String> getDefaultArgs() {
return this.defaultArgs;
}
/**
* Gets the {@link LiteralCommandNode} to be registered for the {@link Command}.
*
* @return the {@link LiteralCommandNode}
*/
public LiteralCommandNode<S> getLiteral() {
return this.literal;
}
/**
* Sets the {@link LiteralCommandNode} used to register this command. The default literal is mutable, so
* this is primarily if you want to completely replace the object.
*
* @param literal new node
*/
public void setLiteral(LiteralCommandNode<S> literal) {
this.literal = literal;
}
/**
* Gets whether this command should is treated as "raw".
*
* @see #setRawCommand(boolean)
* @return whether this command is treated as "raw"
*/
public boolean isRawCommand() {
return this.rawCommand;
}
/**
* Sets whether this command should be treated as "raw".
*
* <p>A "raw" command will only use the node provided by this event for
* sending the command tree to the client. For execution purposes, the default
* greedy string execution of a standard Bukkit {@link Command} is used.</p>
*
* <p>On older versions of Paper, this was the default and only behavior of this
* event.</p>
*
* @param rawCommand whether this command should be treated as "raw"
*/
public void setRawCommand(final boolean rawCommand) {
this.rawCommand = rawCommand;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isCancelled() {
return this.cancelled;
}
/**
* Cancels registering this command to Brigadier, but will remain in Bukkit Command Map. Can be used to hide a
* command from all players.
*
* {@inheritDoc}
*/
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
@NotNull
public HandlerList getHandlers() {
return handlers;
}
@NotNull
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,42 +0,0 @@
package io.papermc.paper.brigadier;
import com.mojang.brigadier.Message;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.TextComponent;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Helper methods to bridge the gaps between Brigadier and Paper-MojangAPI.
*/
public final class PaperBrigadier {
private PaperBrigadier() {
throw new RuntimeException("PaperBrigadier is not to be instantiated!");
}
/**
* Create a new Brigadier {@link Message} from a {@link ComponentLike}.
*
* <p>Mostly useful for creating rich suggestion tooltips in combination with other Paper-MojangAPI APIs.</p>
*
* @param componentLike The {@link ComponentLike} to use for the {@link Message} contents
* @return A new Brigadier {@link Message}
*/
public static @NonNull Message message(final @NonNull ComponentLike componentLike) {
return PaperBrigadierProvider.instance().message(componentLike);
}
/**
* Create a new {@link Component} from a Brigadier {@link Message}.
*
* <p>If the {@link Message} was created from a {@link Component}, it will simply be
* converted back, otherwise a new {@link TextComponent} will be created with the
* content of {@link Message#getString()}</p>
*
* @param message The {@link Message} to create a {@link Component} from
* @return The created {@link Component}
*/
public static @NonNull Component componentFromMessage(final @NonNull Message message) {
return PaperBrigadierProvider.instance().componentFromMessage(message);
}
}

View file

@ -1,30 +0,0 @@
package io.papermc.paper.brigadier;
import com.mojang.brigadier.Message;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import static java.util.Objects.requireNonNull;
interface PaperBrigadierProvider {
final class Holder {
private static @MonotonicNonNull PaperBrigadierProvider INSTANCE;
}
static @NonNull PaperBrigadierProvider instance() {
return requireNonNull(Holder.INSTANCE, "PaperBrigadierProvider has not yet been initialized!");
}
static void initialize(final @NonNull PaperBrigadierProvider instance) {
if (Holder.INSTANCE != null) {
throw new IllegalStateException("PaperBrigadierProvider has already been initialized!");
}
Holder.INSTANCE = instance;
}
@NonNull Message message(@NonNull ComponentLike componentLike);
@NonNull Component componentFromMessage(@NonNull Message message);
}

View file

@ -11,7 +11,7 @@ import kotlin.io.path.*
plugins { plugins {
java java
`maven-publish` `maven-publish`
id("io.papermc.paperweight.core") version "1.6.3" id("io.papermc.paperweight.core") version "1.7.1"
} }
allprojects { allprojects {
@ -109,7 +109,6 @@ paperweight {
tasks.generateDevelopmentBundle { tasks.generateDevelopmentBundle {
apiCoordinates = "io.papermc.paper:paper-api" apiCoordinates = "io.papermc.paper:paper-api"
mojangApiCoordinates = "io.papermc.paper:paper-mojangapi"
libraryRepositories.addAll( libraryRepositories.addAll(
"https://repo.maven.apache.org/maven2/", "https://repo.maven.apache.org/maven2/",
paperMavenPublicUrl, paperMavenPublicUrl,

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ Subject: [PATCH] Plugin remapping
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev> Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index 65fb16941fa7e3a9b300696fb6bd2b562bca48cd..5ffd1d7c130e01a4a7516b361e48bfaf41d4f321 100644 index 66cdd81e4b65ce00973f86763cea566e43053722..2868eb8f9e577ce839d7ecf5ce8fed5bad957dbe 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -46,6 +46,7 @@ dependencies { @@ -46,6 +46,7 @@ dependencies {
@ -1553,17 +1553,17 @@ index 0000000000000000000000000000000000000000..badff5d6ae6dd8d209c82bc7e8afe370
+ } + }
+} +}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index c25d80a1d5aa0f3cc2cbf1e9b94154c759aab36e..c836204a04ca050988057dcc92c7a1fbcc02ef34 100644 index c25d80a1d5aa0f3cc2cbf1e9b94154c759aab36e..cbbd9aaeb0d87aae72edc7fb5aa10920834de8bf 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -637,6 +637,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -636,6 +636,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
this.connection.acceptConnections();
} }
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
this.connection.acceptConnections();
}
@@ -909,6 +910,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -909,6 +910,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.disablePlugins(); this.server.disablePlugins();
} }
@ -1904,14 +1904,14 @@ index 0000000000000000000000000000000000000000..73b20a92f330311e3fef8f03b51a0985
+ } + }
+} +}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 45160b93a24dc74f6368441e2a4fe659ceaf5bf5..6573e72d041714ccc2bf0e3c8734bc212caf534e 100644 index 45160b93a24dc74f6368441e2a4fe659ceaf5bf5..48be9bd462abba1f82200fe3425c36bf8ec91beb 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -966,6 +966,7 @@ public final class CraftServer implements Server { @@ -965,6 +965,7 @@ public final class CraftServer implements Server {
this.loadPlugins();
this.enablePlugins(PluginLoadOrder.STARTUP); this.enablePlugins(PluginLoadOrder.STARTUP);
this.enablePlugins(PluginLoadOrder.POSTWORLD); this.enablePlugins(PluginLoadOrder.POSTWORLD);
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
+ if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins + if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
} }
@Override

View file

@ -18,7 +18,7 @@ index 9a1a961eabd4362c171da78c6be82c867f3696a4..1d0c473442b5c72245c356054440323e
ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerPrefix); ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerPrefix);
ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerSuffix); ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerSuffix);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 4dc8fcd8e118a1c2f5fac0fc291b5555abeec124..53a344b3ee3813872f5f061aab660bf602b573a5 100644 index 4712da0fcc454c1747e2677be821959c6f845f5e..6a5f4e8feb3c88662a78575590998efdf529bb51 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -636,6 +636,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -636,6 +636,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@ -40,8 +40,8 @@ index 4dc8fcd8e118a1c2f5fac0fc291b5555abeec124..53a344b3ee3813872f5f061aab660bf6
+ // Paper end - Configurable player collision + // Paper end - Configurable player collision
+ +
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD); this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index abb769cbbed17a82ee86a6c99e61a375045d9937..3fb300026e627313c65ea23b9c0a9f57a97fa310 100644 index abb769cbbed17a82ee86a6c99e61a375045d9937..3fb300026e627313c65ea23b9c0a9f57a97fa310 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java --- a/src/main/java/net/minecraft/server/players/PlayerList.java

View file

@ -9,7 +9,7 @@ thread dumps at an interval until the point of crash.
This will help diagnose what was going on in that time before the crash. This will help diagnose what was going on in that time before the crash.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 478445e7ed67b17d7aff0e10e9aae0788605a4b9..077b2e1d06a4bb0c2ce10274dc6144ee76608d90 100644 index 8f5eaecb0bda3c4d69bb077ca727458f3f190f44..5fe925b85a7783e3b972d24e01cfe4a4b878dd38 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1104,6 +1104,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -1104,6 +1104,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@ -33,7 +33,7 @@ index 0ffa25a6e41cc56e78c79e0cee45e3b811794129..1b47e228ad7365b31d6ddd8c572d3bc5
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index cbdfb4168f23bbbd37675da6dc88acb3191d88d6..9c673642b7c35bc3c443bd66fbcd278073eeccc2 100644 index 77a9c54c77dd12df870eb60d15b381f12392e8d9..9ff04719f0b560c286d97c8ed99b04d3b32900e3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -926,6 +926,7 @@ public final class CraftServer implements Server { @@ -926,6 +926,7 @@ public final class CraftServer implements Server {
@ -46,8 +46,8 @@ index cbdfb4168f23bbbd37675da6dc88acb3191d88d6..9c673642b7c35bc3c443bd66fbcd2780
this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile()); this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile());
@@ -1016,6 +1017,7 @@ public final class CraftServer implements Server { @@ -1016,6 +1017,7 @@ public final class CraftServer implements Server {
this.enablePlugins(PluginLoadOrder.POSTWORLD); this.enablePlugins(PluginLoadOrder.POSTWORLD);
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
this.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.RELOAD));
+ org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload + org.spigotmc.WatchdogThread.hasStarted = true; // Paper - Disable watchdog early timeout on reload
} }

View file

@ -9,18 +9,6 @@ Adds AsyncPlayerSendCommandsEvent
Adds CommandRegisteredEvent Adds CommandRegisteredEvent
- Allows manipulating the CommandNode to add more children/metadata for the client - Allows manipulating the CommandNode to add more children/metadata for the client
diff --git a/build.gradle.kts b/build.gradle.kts
index e9498f78cb6c0973a820f093ff7a31bef44ba27f..db2d67c98c62aa90591fea82e8fb07270699d96c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,6 +13,7 @@ val alsoShade: Configuration by configurations.creating
dependencies {
implementation(project(":paper-api"))
+ implementation(project(":paper-mojangapi"))
// Paper start
implementation("org.jline:jline-terminal-jansi:3.21.0")
implementation("net.minecrell:terminalconsoleappender:1.3.0")
diff --git a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java diff --git a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java b/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java
index 3370731ee064d2693b972a0765c13dd4fd69f66a..09d486a05179b9d878e1c33725b4e614c3544da9 100644 index 3370731ee064d2693b972a0765c13dd4fd69f66a..09d486a05179b9d878e1c33725b4e614c3544da9 100644
--- a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java --- a/src/main/java/com/mojang/brigadier/exceptions/CommandSyntaxException.java

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Implement Mob Goal API
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index db2d67c98c62aa90591fea82e8fb07270699d96c..7a70c2c52dec44d6b6c7acc7140b2619e56646d0 100644 index 158779a3590f089c4224b2b128c2e653aef42a94..4f8b8839f4d345f448d30de21ad9f3ad7422f98b 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -41,6 +41,7 @@ dependencies { @@ -40,6 +40,7 @@ dependencies {
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
@ -773,7 +773,7 @@ index 6667ecc4b7eded4e20a415cef1e1b1179e6710b8..16f9a98b8a939e5ca7e2dc04f87134a7
LOOK, LOOK,
JUMP, JUMP,
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index c62936e7070d794aeac7e5175757aa045a6afcae..82d462fbc8936b70169ca3b55d488e1ef76aec40 100644 index 821e50c456679f69a9b6ae058f35b601bf3c759b..bd4c982ba919f0196723b4c45be102b47054a70f 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2907,5 +2907,11 @@ public final class CraftServer implements Server { @@ -2907,5 +2907,11 @@ public final class CraftServer implements Server {

View file

@ -51,21 +51,19 @@ index 3728b051b9eb9e9e06bc765a9a2fae7f45daf6ff..779fee2f9b819124a01b9f8d2b7ed0d5
} }
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
index 5e6645e16b185aaa6f719055ddbf670b8741fead..bda9a0b99184adce28bb7851612ed7f4e324826d 100644 index 5e6645e16b185aaa6f719055ddbf670b8741fead..98d314cd293d462ef109e952f3239e08e14dda59 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java --- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
@@ -86,7 +86,23 @@ public final class VanillaCommandWrapper extends BukkitCommand { @@ -86,7 +86,21 @@ public final class VanillaCommandWrapper extends BukkitCommand {
} }
public static String getPermission(CommandNode<CommandSourceStack> vanillaCommand) { public static String getPermission(CommandNode<CommandSourceStack> vanillaCommand) {
- return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName()); - return "minecraft.command." + ((vanillaCommand.getRedirect() == null) ? vanillaCommand.getName() : vanillaCommand.getRedirect().getName());
+ // Paper start - Vanilla command permission fixes + // Paper start - Vanilla command permission fixes
+ final String commandName; + while (vanillaCommand.getRedirect() != null) {
+ if (vanillaCommand.getRedirect() == null) { + vanillaCommand = vanillaCommand.getRedirect();
+ commandName = vanillaCommand.getName();
+ } else {
+ commandName = vanillaCommand.getRedirect().getName();
+ } + }
+ final String commandName = vanillaCommand.getName();
+ return "minecraft.command." + stripDefaultNamespace(commandName); + return "minecraft.command." + stripDefaultNamespace(commandName);
+ } + }
+ +

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Add support for Proxy Protocol
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index 7a70c2c52dec44d6b6c7acc7140b2619e56646d0..9b9e744d18cf66279f51f950b6ecce31415f9fa8 100644 index 4f8b8839f4d345f448d30de21ad9f3ad7422f98b..1ed8d1ba75fa3a31469a6e8e3b661328b0debf12 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies { @@ -27,6 +27,7 @@ dependencies {
log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins
runtimeOnly(log4jPlugins.output) runtimeOnly(log4jPlugins.output)
alsoShade(log4jPlugins.output) alsoShade(log4jPlugins.output)

View file

@ -5,10 +5,10 @@ Subject: [PATCH] Use Velocity compression and cipher natives
diff --git a/build.gradle.kts b/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts
index 9b9e744d18cf66279f51f950b6ecce31415f9fa8..5d448d8a7cf6626a11791f30ad52baf41a099272 100644 index 1ed8d1ba75fa3a31469a6e8e3b661328b0debf12..87bb3fd9b97506f61734ae7f2e6860610ba794e7 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -37,6 +37,11 @@ dependencies { @@ -36,6 +36,11 @@ dependencies {
runtimeOnly("org.xerial:sqlite-jdbc:3.45.3.0") runtimeOnly("org.xerial:sqlite-jdbc:3.45.3.0")
runtimeOnly("com.mysql:mysql-connector-j:8.3.0") runtimeOnly("com.mysql:mysql-connector-j:8.3.0")
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper runtimeOnly("com.lmax:disruptor:3.4.4") // Paper

View file

@ -226,13 +226,13 @@ index 0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a..47355158e5e762540a10dc67b23092a0
private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException { private static int giveItem(CommandSourceStack source, ItemInput item, Collection<ServerPlayer> targets, int count) throws CommandSyntaxException {
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
index 61115db85b81e627d11a0de21691a2ca69aafe2c..ba2a2ca0c36e61cb3cc00fafc7a5dd9f7050388f 100644 index 2ee33c55890fa659f6d251e486264c85d9e89802..dd1507f65a7f1d84bc7f236f81a60ac1302a13b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java --- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
@@ -98,6 +98,9 @@ public final class VanillaCommandWrapper extends BukkitCommand { @@ -96,6 +96,9 @@ public final class VanillaCommandWrapper extends BukkitCommand {
} else { vanillaCommand = vanillaCommand.getRedirect();
commandName = vanillaCommand.getRedirect().getName();
} }
final String commandName = vanillaCommand.getName();
+ if ("pgive".equals(stripDefaultNamespace(commandName))) { + if ("pgive".equals(stripDefaultNamespace(commandName))) {
+ return "bukkit.command.paper.pgive"; + return "bukkit.command.paper.pgive";
+ } + }

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,7 @@ if (!file(".git").exists()) {
rootProject.name = "paper" rootProject.name = "paper"
for (name in listOf("Paper-API", "Paper-Server", "Paper-MojangAPI")) { for (name in listOf("Paper-API", "Paper-Server")) {
val projName = name.lowercase(Locale.ENGLISH) val projName = name.lowercase(Locale.ENGLISH)
include(projName) include(projName)
findProject(":$projName")!!.projectDir = file(name) findProject(":$projName")!!.projectDir = file(name)

View file

@ -2,7 +2,6 @@ version = "1.0.0-SNAPSHOT"
dependencies { dependencies {
compileOnly(project(":paper-api")) compileOnly(project(":paper-api"))
compileOnly(project(":paper-mojangapi"))
} }
tasks.processResources { tasks.processResources {

View file

@ -8,5 +8,8 @@ public final class TestPlugin extends JavaPlugin implements Listener {
@Override @Override
public void onEnable() { public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this); this.getServer().getPluginManager().registerEvents(this, this);
// io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this);
} }
} }

View file

@ -8,6 +8,7 @@ public class TestPluginBootstrap implements PluginBootstrap {
@Override @Override
public void bootstrap(@NotNull BootstrapContext context) { public void bootstrap(@NotNull BootstrapContext context) {
// io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context);
} }
} }

View file

@ -0,0 +1,166 @@
package io.papermc.testplugin.brigtests;
import com.mojang.brigadier.Command;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import io.papermc.paper.command.brigadier.argument.range.DoubleRangeProvider;
import io.papermc.paper.plugin.bootstrap.BootstrapContext;
import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import io.papermc.testplugin.brigtests.example.ExampleAdminCommand;
import io.papermc.testplugin.brigtests.example.MaterialArgumentType;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.BukkitCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
public final class Registration {
private Registration() {
}
public static void registerViaOnEnable(final JavaPlugin plugin) {
registerLegacyCommands(plugin);
registerViaLifecycleEvents(plugin);
}
private static void registerViaLifecycleEvents(final JavaPlugin plugin) {
final LifecycleEventManager<Plugin> lifecycleManager = plugin.getLifecycleManager();
lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
final Commands commands = event.registrar();
// ensure plugin commands override
commands.register(Commands.literal("tag")
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage("overriden command");
return Command.SINGLE_SUCCESS;
})
.build(),
null,
Collections.emptyList()
);
});
lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> {
final Commands commands = event.registrar();
commands.register(plugin.getPluginMeta(), Commands.literal("root_command")
.then(Commands.literal("sub_command")
.requires(source -> source.getSender().hasPermission("testplugin.test"))
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage("root_command sub_command");
return Command.SINGLE_SUCCESS;
})).build(),
null,
Collections.emptyList()
);
commands.register(plugin.getPluginMeta(), "example", "test", Collections.emptyList(), new BasicCommand() {
@Override
public void execute(@NotNull final CommandSourceStack commandSourceStack, final @NotNull String[] args) {
System.out.println(Arrays.toString(args));
}
@Override
public @NotNull Collection<String> suggest(final @NotNull CommandSourceStack commandSourceStack, final @NotNull String[] args) {
System.out.println(Arrays.toString(args));
return List.of("apple", "banana");
}
});
commands.register(plugin.getPluginMeta(), Commands.literal("water")
.requires(source -> {
System.out.println("isInWater check");
return source.getExecutor().isInWater();
})
.executes(ctx -> {
ctx.getSource().getExecutor().sendMessage("You are in water!");
return Command.SINGLE_SUCCESS;
}).then(Commands.literal("lava")
.requires(source -> {
System.out.println("isInLava check");
if (source.getExecutor() != null) {
return source.getExecutor().isInLava();
}
return true;
})
.executes(ctx -> {
ctx.getSource().getExecutor().sendMessage("You are in lava!");
return Command.SINGLE_SUCCESS;
})).build(),
null,
Collections.emptyList());
ExampleAdminCommand.register(plugin, commands);
}).priority(10));
}
private static void registerLegacyCommands(final JavaPlugin plugin) {
plugin.getServer().getCommandMap().register("fallback", new BukkitCommand("hi", "cool hi command", "<>", List.of("hialias")) {
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
sender.sendMessage("hi");
return true;
}
});
plugin.getServer().getCommandMap().register("fallback", new BukkitCommand("cooler-command", "cool hi command", "<>", List.of("cooler-command-alias")) {
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
sender.sendMessage("hi");
return true;
}
});
plugin.getServer().getCommandMap().getKnownCommands().values().removeIf((command) -> {
return command.getName().equals("hi");
});
}
public static void registerViaBootstrap(final BootstrapContext context) {
final LifecycleEventManager<BootstrapContext> lifecycleManager = context.getLifecycleManager();
lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
final Commands commands = event.registrar();
commands.register(Commands.literal("material")
.then(Commands.literal("item")
.then(Commands.argument("mat", MaterialArgumentType.item())
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("mat", Material.class).name());
return Command.SINGLE_SUCCESS;
})
)
).then(Commands.literal("block")
.then(Commands.argument("mat", MaterialArgumentType.block())
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("mat", Material.class).name());
return Command.SINGLE_SUCCESS;
})
)
)
.build(),
null,
Collections.emptyList()
);
});
lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> {
final Commands commands = event.registrar();
commands.register(Commands.literal("heya")
.then(Commands.argument("range", ArgumentTypes.doubleRange())
.executes((ct) -> {
ct.getSource().getSender().sendPlainMessage(ct.getArgument("range", DoubleRangeProvider.class).range().toString());
return 1;
})
).build(),
null,
Collections.emptyList()
);
}).priority(10));
}
}

View file

@ -0,0 +1,25 @@
package io.papermc.testplugin.brigtests.example;
import com.mojang.brigadier.ImmutableStringReader;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.exceptions.CommandExceptionType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.papermc.paper.command.brigadier.MessageComponentSerializer;
import net.kyori.adventure.text.Component;
public class ComponentCommandExceptionType implements CommandExceptionType {
private final Message message;
public ComponentCommandExceptionType(final Component message) {
this.message = MessageComponentSerializer.message().serialize(message);
}
public CommandSyntaxException create() {
return new CommandSyntaxException(this, this.message);
}
public CommandSyntaxException createWithContext(final ImmutableStringReader reader) {
return new CommandSyntaxException(this, this.message, reader.getString(), reader.getCursor());
}
}

View file

@ -0,0 +1,154 @@
package io.papermc.testplugin.brigtests.example;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.command.brigadier.argument.SignedMessageResolver;
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import io.papermc.paper.command.brigadier.argument.resolvers.BlockPositionResolver;
import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver;
import io.papermc.paper.math.BlockPosition;
import io.papermc.testplugin.TestPlugin;
import net.kyori.adventure.chat.ChatType;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ExampleAdminCommand {
public static void register(JavaPlugin plugin, Commands commands) {
final LiteralArgumentBuilder<CommandSourceStack> adminBuilder = Commands.literal("admin")
.executes((ct) -> {
ct.getSource().getSender().sendPlainMessage("root admin");
return 1;
})
.then(
Commands.literal("tp")
.then(
Commands.argument("player", ArgumentTypes.player()).executes((source) -> {
CommandSourceStack sourceStack = source.getSource();
Player resolved = source.getArgument("player", PlayerSelectorArgumentResolver.class).resolve(sourceStack).get(0);
if (resolved == source.getSource().getExecutor()) {
source.getSource().getExecutor().sendMessage(Component.text("Can't teleport to self!"));
return 0;
}
Entity entity = source.getSource().getExecutor();
if (entity != null) {
entity.teleport(resolved);
}
return 1;
})
)
)
.then(
Commands.literal("tp-self")
.executes((cmd) -> {
if (cmd.getSource().getSender() instanceof Player player) {
player.teleport(cmd.getSource().getLocation());
}
return com.mojang.brigadier.Command.SINGLE_SUCCESS;
})
)
.then(
Commands.literal("broadcast")
.then(
Commands.argument("message", ArgumentTypes.component()).executes((source) -> {
Component message = source.getArgument("message", Component.class);
Bukkit.broadcast(message);
return 1;
})
)
)
.then(
Commands.literal("ice_cream").then(
Commands.argument("type", new IceCreamTypeArgument()).executes((context) -> {
IceCreamType argumentResponse = context.getArgument("type", IceCreamType.class); // Gets the raw argument
context.getSource().getSender().sendMessage(Component.text("You like: " + argumentResponse));
return 1;
})
)
)
.then(
Commands.literal("execute")
.redirect(commands.getDispatcher().getRoot().getChild("execute"))
)
.then(
Commands.literal("signed_message").then(
Commands.argument("msg", ArgumentTypes.signedMessage()).executes((context) -> {
SignedMessageResolver argumentResponse = context.getArgument("msg", SignedMessageResolver.class); // Gets the raw argument
// This is a better way of getting signed messages, includes the concept of "disguised" messages.
argumentResponse.resolveSignedMessage("msg", context)
.thenAccept((signedMsg) -> {
context.getSource().getSender().sendMessage(signedMsg, ChatType.SAY_COMMAND.bind(Component.text("STATIC")));
});
return 1;
})
)
)
.then(
Commands.literal("setblock").then(
Commands.argument("block", ArgumentTypes.blockState())
.then(Commands.argument("pos", ArgumentTypes.blockPosition())
.executes((context) -> {
CommandSourceStack sourceStack = context.getSource();
BlockPosition position = context.getArgument("pos", BlockPositionResolver.class).resolve(sourceStack);
BlockState state = context.getArgument("block", BlockState.class);
// TODO: better block state api here? :thinking:
Block block = context.getSource().getLocation().getWorld().getBlockAt(position.blockX(), position.blockY(), position.blockZ());
block.setType(state.getType());
block.setBlockData(state.getBlockData());
return 1;
})
)
)
);
commands.register(plugin.getPluginMeta(), adminBuilder.build(), "Cool command showcasing what you can do!", List.of("alias_for_admin_that_you_shouldnt_use", "a"));
Bukkit.getCommandMap().register(
"legacy",
new Command("legacy_command") {
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
throw new UnsupportedOperationException();
}
@Override
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
return List.of(String.join(" ", args));
}
}
);
Bukkit.getCommandMap().register(
"legacy",
new Command("legacy_fail") {
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
return false;
}
@Override
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException {
return List.of(String.join(" ", args));
}
}
);
}
}

View file

@ -0,0 +1,9 @@
package io.papermc.testplugin.brigtests.example;
public enum IceCreamType {
VANILLA,
CHOCOLATE,
BLUE_MOON,
STRAWBERRY,
WHOLE_MILK
}

View file

@ -0,0 +1,47 @@
package io.papermc.testplugin.brigtests.example;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.papermc.paper.command.brigadier.MessageComponentSerializer;
import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
public class IceCreamTypeArgument implements CustomArgumentType.Converted<IceCreamType, String> {
@Override
public @NotNull IceCreamType convert(String nativeType) throws CommandSyntaxException {
try {
return IceCreamType.valueOf(nativeType.toUpperCase());
} catch (Exception e) {
Message message = MessageComponentSerializer.message().serialize(Component.text("Invalid species %s!".formatted(nativeType), NamedTextColor.RED));
throw new CommandSyntaxException(new SimpleCommandExceptionType(message), message);
}
}
@Override
public @NotNull ArgumentType<String> getNativeType() {
return StringArgumentType.word();
}
@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
for (IceCreamType species : IceCreamType.values()) {
builder.suggest(species.name(), MessageComponentSerializer.message().serialize(Component.text("COOL! TOOLTIP!", NamedTextColor.GREEN)));
}
return CompletableFuture.completedFuture(
builder.build()
);
}
}

View file

@ -0,0 +1,88 @@
package io.papermc.testplugin.brigtests.example;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.papermc.paper.command.brigadier.argument.CustomArgumentType;
import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.bukkit.Keyed;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.jetbrains.annotations.NotNull;
import static net.kyori.adventure.text.Component.translatable;
public class MaterialArgumentType implements CustomArgumentType.Converted<Material, NamespacedKey> {
private static final ComponentCommandExceptionType ERROR_INVALID = new ComponentCommandExceptionType(translatable("argument.id.invalid"));
private final Predicate<Material> check;
private MaterialArgumentType(Predicate<Material> check) {
this.check = check;
}
public static MaterialArgumentType item() {
return new MaterialArgumentType(Material::isItem);
}
public static MaterialArgumentType block() {
return new MaterialArgumentType(Material::isBlock);
}
@Override
public @NotNull Material convert(final @NotNull NamespacedKey nativeType) throws CommandSyntaxException {
final Material material = Registry.MATERIAL.get(nativeType);
if (material == null) {
throw ERROR_INVALID.create();
}
if (!this.check.test(material)) {
throw ERROR_INVALID.create();
}
return material;
}
static boolean matchesSubStr(String remaining, String candidate) {
for(int i = 0; !candidate.startsWith(remaining, i); ++i) {
i = candidate.indexOf('_', i);
if (i < 0) {
return false;
}
}
return true;
}
@Override
public @NotNull ArgumentType<NamespacedKey> getNativeType() {
return ArgumentTypes.namespacedKey();
}
@Override
public @NotNull <S> CompletableFuture<Suggestions> listSuggestions(final @NotNull CommandContext<S> context, final @NotNull SuggestionsBuilder builder) {
final Stream<Material> stream = StreamSupport.stream(Registry.MATERIAL.spliterator(), false);
final String remaining = builder.getRemaining();
boolean containsColon = remaining.indexOf(':') > -1;
stream.filter(this.check)
.map(Keyed::key)
.forEach(key -> {
final String keyAsString = key.asString();
if (containsColon) {
if (matchesSubStr(remaining, keyAsString)) {
builder.suggest(keyAsString);
}
} else if (matchesSubStr(remaining, key.namespace()) || "minecraft".equals(key.namespace()) && matchesSubStr(remaining, key.value())) {
builder.suggest(keyAsString);
}
});
return builder.buildFuture();
}
}