agentsclimarketplace

Events

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

Minecraft Java Plugin Claude SkillsFrom the repository description

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

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

5.9 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it

Events Skill — Paper

Purpose

Reference this skill when implementing event listeners on a Paper server. Covers event registration, priority ordering, cancellation, and thread-safety rules for all Bukkit/Paper events.

When to Use This Skill

  • Adding a listener for any org.bukkit.event.* or io.papermc.paper.event.* event
  • Deciding event priority for overlapping listeners
  • Handling cancellable events correctly
  • Working with async events (especially chat)

API Quick Reference

Class / MethodPurposeNotes
Listener (interface)Marker interface for event listener classesRequired on listener class
@EventHandlerMarks a method as an event handlerMethod must have exactly one event parameter
EventPriorityControls listener order: LOWEST → LOW → NORMAL → HIGH → HIGHEST → MONITORMONITOR = read-only, never cancel here
ignoreCancelled = trueSkip handler if event already cancelledRecommended for most handlers
PluginManager#registerEvents(Listener, Plugin)Register all @EventHandler methods in a listenerCall once in onEnable
HandlerList#unregisterAll(Plugin)Unregister all listeners for a pluginCalled automatically on onDisable
Event#isCancelled()Check if event is already cancelled
Cancellable#setCancelled(boolean)Cancel the eventPrevents default action
AsyncChatEventPaper's modern async chat eventReplaces deprecated AsyncPlayerChatEvent

Code Pattern

package com.yourorg.myplugin.events;

import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.java.JavaPlugin;

public class PlayerJoinListener implements Listener {

    private final JavaPlugin plugin;

    public PlayerJoinListener(JavaPlugin plugin) {
        this.plugin = plugin;
    }

    // Standard listener: NORMAL priority, skip if already cancelled
    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();

        // Set custom join message using Adventure components
        event.joinMessage(Component.text("+ ")
            .color(NamedTextColor.GREEN)
            .append(Component.text(player.getName())
                .color(NamedTextColor.WHITE)));
    }

    @EventHandler(priority = EventPriority.NORMAL)
    public void onPlayerQuit(PlayerQuitEvent event) {
        Player player = event.getPlayer();

        event.quitMessage(Component.text("- ")
            .color(NamedTextColor.RED)
            .append(Component.text(player.getName())
                .color(NamedTextColor.WHITE)));
    }

    // Async chat event — DO NOT call Bukkit object mutations here
    @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
    public void onChat(AsyncChatEvent event) {
        Player player = event.getPlayer();
        Component originalMessage = event.message();

        // Reading player data: safe (immutable snapshot)
        String name = player.getName();

        // Modifying the message: safe (event object, not Bukkit world state)
        event.message(Component.text("[Chat] ")
            .color(NamedTextColor.GRAY)
            .append(originalMessage));

        // NOT safe here: player.teleport(), world.dropItem(), etc.
        // If you must do Bukkit ops, schedule back to main thread:
        // Bukkit.getScheduler().runTask(plugin, () -> { ... });
    }
}

Registering the listener in your main class:

@Override
public void onEnable() {
    getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
}

Common Pitfalls

  • Calling Bukkit methods from async event handlers: AsyncChatEvent fires on an async thread. Calling player.teleport(), world.dropItem(), or any world-mutating method will throw IllegalStateException or cause data corruption. Schedule back to main thread with Bukkit.getScheduler().runTask(plugin, runnable).

  • Using MONITOR priority to cancel events: MONITOR is for read-only observation after all other plugins have processed the event. Cancelling at MONITOR is undefined behavior and may be ignored.

  • Not using ignoreCancelled = true: Without it, your handler fires even when another plugin has already cancelled the event, potentially overriding that decision. Add ignoreCancelled = true unless you specifically need to handle already-cancelled events.

  • Registering listeners multiple times: Calling registerEvents() twice on the same listener instance doubles all event firings. Register each listener exactly once in onEnable.

  • Still using AsyncPlayerChatEvent: This event is deprecated in Paper 1.19+ and removed in some builds. Use AsyncChatEvent from io.papermc.paper.event.player instead.

Version Notes

  • 1.21: AsyncChatEvent is the standard chat event. AsyncPlayerChatEvent is deprecated.
  • 1.21.1: No breaking changes to event API vs 1.21.
  • Both: PlayerMoveEvent fires very frequently (every tick a player is loaded). Use event.hasExplicitlyMoved() or event.hasChangedPosition() to filter out head rotations.

Related Skills

What ships with it: 4 files

29.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.