Compare commits

...
Author SHA1 Message Date
Jason Penilla e086eba479 Use preconditions 2025-10-07 12:55:38 -07:00
Jason Penilla f1a5d1fe3c rename sendSystemMessage 2025-10-07 12:54:18 -07:00
Jason Penilla 05f3801237 remove supplier API 2025-10-07 12:54:18 -07:00
Jason Penilla 55f359243b Adjust brig tests 2025-10-07 12:54:18 -07:00
Jason Penilla 033263f5b4 fix compile 2025-10-07 12:54:18 -07:00
Jason Penilla 35129eb522 Add helper methods for vanilla-style command feedback 2025-10-07 12:54:14 -07:00
3 changed files with 84 additions and 14 deletions

No files matched your search

@@ -2,9 +2,12 @@ package io.papermc.paper.command.brigadier;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.tree.CommandNode;
import net.kyori.adventure.text.ComponentLike;
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.Nullable;
@@ -67,4 +70,34 @@ public interface CommandSourceStack {
* @see com.mojang.brigadier.builder.ArgumentBuilder#fork(CommandNode, RedirectModifier)
*/
CommandSourceStack withExecutor(Entity executor);
/**
* Sends a system message to the {@link #getExecutor()} if it is a {@link Player},
* otherwise sends a system message to the {@link #getSender()}.
*
* @param message the message to send
*/
void sendToTarget(ComponentLike message);
/**
* Sends a system message to the {@link #getSender()}, admins, and console indicating successful command execution
* according to vanilla semantics.
*
* <p>This currently includes checking for environments with suppressed output,
* {@link GameRule#SEND_COMMAND_FEEDBACK}, and {@link GameRule#LOG_ADMIN_COMMANDS}.</p>
*
* @param message the message to send
* @param allowInformingAdmins whether admins and console may be informed of this success
*/
void sendSuccess(ComponentLike message, boolean allowInformingAdmins);
/**
* Sends a system message indicating a failed command execution to the {@link #getSender()}.
* Does not apply red styling to the message as vanilla does to allow for custom failure message styling.
*
* <p>Respects vanilla semantics for accepting failure output and suppressed output environments.</p>
*
* @param message the message to send
*/
void sendFailure(ComponentLike message);
}
@@ -2,6 +2,8 @@ package io.papermc.paper.command.brigadier;
import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource;
import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.ComponentLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
@@ -26,14 +28,12 @@ public interface PaperCommandSourceStack extends CommandSourceStack, BukkitBriga
}
@Override
@NonNull
default CommandSender getSender() {
default @NonNull CommandSender getSender() {
return this.getHandle().getBukkitSender();
}
@Override
@Nullable
default Entity getExecutor() {
default @Nullable Entity getExecutor() {
net.minecraft.world.entity.Entity nmsEntity = this.getHandle().getEntity();
if (nmsEntity == null) {
return null;
@@ -43,11 +43,29 @@ public interface PaperCommandSourceStack extends CommandSourceStack, BukkitBriga
}
@Override
default CommandSourceStack withExecutor(@NonNull Entity executor) {
default @NonNull CommandSourceStack withExecutor(@NonNull Entity executor) {
Preconditions.checkNotNull(executor, "Executor cannot be null.");
return this.getHandle().withEntity(((CraftEntity) executor).getHandle());
}
@Override
default void sendToTarget(final @NonNull ComponentLike message) {
Preconditions.checkNotNull(message, "message cannot be null.");
this.getHandle().sendSystemMessage(PaperAdventure.asVanilla(message.asComponent()));
}
@Override
default void sendSuccess(final @NonNull ComponentLike message, final boolean allowInformingAdmins) {
Preconditions.checkNotNull(message, "message cannot be null.");
this.getHandle().sendSuccess(() -> PaperAdventure.asVanilla(message.asComponent()), allowInformingAdmins);
}
@Override
default void sendFailure(final @NonNull ComponentLike message) {
Preconditions.checkNotNull(message, "message cannot be null.");
this.getHandle().sendFailure(PaperAdventure.asVanilla(message.asComponent()), false);
}
// OLD METHODS
@Override
default org.bukkit.entity.Entity getBukkitEntity() {
@@ -1,6 +1,8 @@
package io.papermc.testplugin.brigtests;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import io.papermc.paper.command.brigadier.BasicCommand;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
@@ -19,6 +21,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.BukkitCommand;
@@ -45,7 +49,7 @@ public final class Registration {
.then(
Commands.argument("name", ArgumentTypes.resource(RegistryKey.ENCHANTMENT))
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("name", Enchantment.class).toString());
ctx.getSource().sendSuccess(Component.text(ctx.getArgument("name", Enchantment.class).toString()), false);
return Command.SINGLE_SUCCESS;
})
).build()
@@ -55,7 +59,7 @@ public final class Registration {
Commands.argument("key", ArgumentTypes.resourceKey(RegistryKey.ENCHANTMENT))
.executes(ctx -> {
final TypedKey<Enchantment> key = RegistryArgumentExtractor.getTypedKey(ctx, RegistryKey.ENCHANTMENT, "key");
ctx.getSource().getSender().sendPlainMessage(key.toString());
ctx.getSource().sendSuccess(Component.text(key.toString()), false);
return Command.SINGLE_SUCCESS;
})
).build()
@@ -65,7 +69,7 @@ public final class Registration {
Commands.argument("pos", ArgumentTypes.finePosition(false))
.executes(ctx -> {
final FinePositionResolver position = ctx.getArgument("pos", FinePositionResolver.class);
ctx.getSource().getSender().sendPlainMessage("Position: " + position.resolve(ctx.getSource()));
ctx.getSource().sendSuccess(Component.text("Position: " + position.resolve(ctx.getSource())), false);
return Command.SINGLE_SUCCESS;
})
).build()
@@ -73,7 +77,7 @@ public final class Registration {
// ensure plugin commands override
commands.register(Commands.literal("tag")
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage("overriden command");
ctx.getSource().sendSuccess(Component.text("overriden command"), false);
return Command.SINGLE_SUCCESS;
})
.build(),
@@ -88,7 +92,7 @@ public final class Registration {
.then(Commands.literal("sub_command")
.requires(source -> source.getSender().hasPermission("testplugin.test"))
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage("root_command sub_command");
ctx.getSource().sendSuccess(Component.text("root_command sub_command"), false);
return Command.SINGLE_SUCCESS;
})).build(),
null,
@@ -165,14 +169,14 @@ public final class Registration {
.then(Commands.literal("item")
.then(Commands.argument("mat", MaterialArgumentType.item())
.executes(ctx -> {
ctx.getSource().getSender().sendPlainMessage(ctx.getArgument("mat", Material.class).name());
ctx.getSource().sendSuccess(Component.text(ctx.getArgument("mat", Material.class).name()), false);
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());
ctx.getSource().sendSuccess(Component.text(ctx.getArgument("mat", Material.class).name()), false);
return Command.SINGLE_SUCCESS;
})
)
@@ -181,6 +185,21 @@ public final class Registration {
null,
Collections.emptyList()
);
commands.register(Commands.literal("send_success")
.then(Commands.argument("allow_inform_admins", BoolArgumentType.bool())
.then(Commands.argument("msg", StringArgumentType.greedyString())
.executes(ctx -> {
ctx.getSource().sendSuccess(
MiniMessage.miniMessage().deserialize(StringArgumentType.getString(ctx, "msg")),
BoolArgumentType.getBool(ctx, "allow_inform_admins")
);
return Command.SINGLE_SUCCESS;
})))
.build(),
null,
Collections.emptyList()
);
});
lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(event -> {
@@ -188,8 +207,8 @@ public final class Registration {
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;
ct.getSource().sendSuccess(Component.text(ct.getArgument("range", DoubleRangeProvider.class).range().toString()), false);
return Command.SINGLE_SUCCESS;
})
).build(),
null,