agentsclimarketplace

Commands

Skill MrPippi/MJP-Claude-Skills/docs/paper/commands

Minecraft Java Plugin Claude SkillsFrom the repository description

Install
npx -y skills add MrPippi/MJP-Claude-Skills --skill commands

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.3 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it

Commands Skill — Paper

Purpose

Reference this skill when registering commands on a Paper 1.21 server. Paper uses native Brigadier via LifecycleEvents.COMMANDS; this skill explains when and how to use it versus the legacy CommandExecutor approach.

When to Use This Skill

  • Creating any /command that players or operators can run
  • Adding tab completion to commands
  • Restricting commands to players with specific permissions
  • Supporting subcommands with typed arguments (integers, players, locations, etc.)

API Quick Reference

Class / MethodPurposeNotes
LifecycleEvents.COMMANDSThe lifecycle event type for command registrationUse with getLifecycleManager().registerEventHandler()
Commands (registrar)The Brigadier command registrar provided by PaperObtained from the lifecycle event
Commands#register(LiteralCommandNode, String)Register a root command node with descriptionDescription appears in /help
Commands.literal(String)Start building a command literal nodeFrom com.mojang.brigadier.builder.LiteralArgumentBuilder via Paper wrapper
Commands.argument(String, ArgumentType<T>)Add a typed argumentFrom Brigadier's argument builder
ArgumentTypesPaper's built-in argument typesArgumentTypes.player(), ArgumentTypes.world(), etc.
StringArgumentType.word()Single-word string argumentFrom com.mojang.brigadier.arguments
IntegerArgumentType.integer(min, max)Bounded integer argument
CommandSourceStackThe command source (wraps CommandSender)Access via ctx.getSource()
ctx.getSource().getSender()Get the underlying CommandSenderCast to Player if needed
Command.SINGLE_SUCCESSReturn value indicating successReturn 1 from executes lambda
.requires(source -> ...)Permission predicate for the commandCheck source.getSender().hasPermission(...)

Code Pattern

package com.yourorg.myplugin.commands;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

public class CommandRegistrar {

    public static void register(JavaPlugin plugin) {
        plugin.getLifecycleManager().registerEventHandler(
            LifecycleEvents.COMMANDS,
            event -> {
                Commands commands = event.registrar();

                // Simple command: /myplugin
                commands.register(
                    Commands.literal("myplugin")
                        .requires(source -> source.getSender().hasPermission("myplugin.use"))
                        .executes(ctx -> executeRoot(ctx))
                        // Subcommand: /myplugin info <playerName>
                        .then(Commands.literal("info")
                            .then(Commands.argument("player", StringArgumentType.word())
                                .executes(ctx -> executeInfo(ctx))))
                        // Subcommand: /myplugin level <number>
                        .then(Commands.literal("level")
                            .requires(source -> source.getSender().hasPermission("myplugin.admin"))
                            .then(Commands.argument("amount", IntegerArgumentType.integer(1, 100))
                                .executes(ctx -> executeLevel(ctx))))
                        .build(),
                    "MyPlugin main command"
                );
            }
        );
    }

    private static int executeRoot(CommandContext<CommandSourceStack> ctx) {
        CommandSender sender = ctx.getSource().getSender();
        sender.sendMessage(Component.text("MyPlugin v1.0.0").color(NamedTextColor.GOLD));
        return Command.SINGLE_SUCCESS;
    }

    private static int executeInfo(CommandContext<CommandSourceStack> ctx) {
        CommandSender sender = ctx.getSource().getSender();
        String targetName = StringArgumentType.getString(ctx, "player");

        Player target = sender.getServer().getPlayer(targetName);
        if (target == null) {
            sender.sendMessage(Component.text("Player not found: " + targetName)
                .color(NamedTextColor.RED));
            return 0;   // return 0 to signal failure
        }

        sender.sendMessage(Component.text("Player: " + target.getName())
            .color(NamedTextColor.AQUA));
        return Command.SINGLE_SUCCESS;
    }

    private static int executeLevel(CommandContext<CommandSourceStack> ctx) {
        CommandSender sender = ctx.getSource().getSender();

        // Only allow players (not console) for level command
        if (!(sender instanceof Player player)) {
            sender.sendMessage(Component.text("Only players can use this command.")
                .color(NamedTextColor.RED));
            return 0;
        }

        int amount = IntegerArgumentType.getInteger(ctx, "amount");
        player.setLevel(player.getLevel() + amount);
        player.sendMessage(Component.text("Level set to " + player.getLevel())
            .color(NamedTextColor.GREEN));
        return Command.SINGLE_SUCCESS;
    }
}

Call from main class onEnable:

CommandRegistrar.register(this);

Common Pitfalls

  • Mixing Brigadier with plugin.yml command declarations: Brigadier commands registered via LifecycleEvents.COMMANDS do NOT need to be declared in plugin.yml. Declaring them there AND in Brigadier causes duplicate registration in some builds.

  • Returning 0 without a message: When a command fails, always send an error message before returning 0. Silent failures confuse players.

  • Using CommandSender as Player without checking: Console can run commands too. Always instanceof check before casting: if (sender instanceof Player player) { ... }.

  • Registering commands outside LifecycleEvents.COMMANDS: Calling Commands.register() directly in onEnable() (not inside the lifecycle handler) is not supported and will throw an error.

  • Forgetting .requires() for admin commands: Without a permission check, any player can run admin subcommands.

Version Notes

  • 1.21: LifecycleEvents.COMMANDS is the supported way to register Brigadier commands. Legacy CommandExecutor still works but does not support typed arguments or native client-side suggestions.
  • 1.21.1: No breaking changes to command API.
  • Both: Tab completion for Brigadier arguments is automatic — clients see valid options natively without any SuggestionProvider for built-in types. See command-completion.md for custom suggestions.

Related Skills

What ships with it: 2 files

17.6 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.