Reference this skill when handling Purpur-specific events that are not available in Paper. All Paper events are also available in Purpur — this skill covers only the additional events provided by Purpur's API.
When to Use This Skill
Detecting when a player goes AFK or returns from AFK
Responding to Purpur-extended entity/damage events
Writing a plugin that specifically targets Purpur (not cross-platform)
API Quick Reference
Class / Method
Purpose
Notes
PlayerAFKEvent
Player becomes AFK
Requires afk-timeout set in purpur.yml
PlayerNotAFKEvent
Player returns from AFK
EntityAirChangeEvent
Entity's air supply changes
Cancellable
PlayerAFKEvent#getPlayer()
Player going AFK
PlayerAFKEvent#isGoingAFK()
Always true for AFK event
Use PlayerNotAFKEvent for return
Code Pattern
package com.yourorg.myplugin.events;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.purpurmc.purpur.event.entity.EntityAirChangeEvent;
import org.purpurmc.purpur.event.player.PlayerAFKEvent;
import org.purpurmc.purpur.event.player.PlayerNotAFKEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
public class PurpurEventListener implements Listener {
// --- AFK Events ---
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerAFK(PlayerAFKEvent event) {
Player player = event.getPlayer();
// Notify the player
player.sendActionBar(
Component.text("You are now AFK.").color(NamedTextColor.GRAY)
);
// Broadcast to the server
player.getServer().broadcast(
Component.text(player.getName() + " is now AFK.")
.color(NamedTextColor.YELLOW)
);
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerReturnFromAFK(PlayerNotAFKEvent event) {
Player player = event.getPlayer();
player.sendActionBar(
Component.text("Welcome back!").color(NamedTextColor.GREEN)
);
player.getServer().broadcast(
Component.text(player.getName() + " is no longer AFK.")
.color(NamedTextColor.YELLOW)
);
}
// --- Entity Air Change ---
@EventHandler(priority = EventPriority.NORMAL)
public void onEntityAirChange(EntityAirChangeEvent event) {
// Example: prevent players from losing air underwater
if (event.getEntity() instanceof Player player
&& player.hasPermission("myplugin.no-drown")) {
event.setCancelled(true);
}
}
}
Guard Purpur-only registration:
// In main class onEnable — only register if running on Purpur
try {
Class.forName("org.purpurmc.purpur.event.player.PlayerAFKEvent");
getServer().getPluginManager().registerEvents(new PurpurEventListener(), this);
getSLF4JLogger().info("Purpur events registered.");
} catch (ClassNotFoundException e) {
getSLF4JLogger().info("Not running on Purpur — Purpur-specific events skipped.");
}
Common Pitfalls
Registering Purpur listeners on a Paper server: If your plugin runs on plain Paper, Purpur event classes are absent. The registration itself (calling registerEvents) will throw ClassNotFoundException at plugin load time. Always guard with a try/catch or softdepend: [Purpur] and a runtime check.
Depending on AFK without configuring purpur.yml: PlayerAFKEvent only fires if gameplay-mechanics.afk-timeout is set to a positive value in purpur.yml. With the default of 0 (disabled), the event never fires.
Assuming Purpur event package paths are the same as Paper: Purpur events are under org.purpurmc.purpur.event.*, NOT io.papermc.paper.event.*.
Version Notes
Purpur 1.21.1: PlayerAFKEvent and PlayerNotAFKEvent are stable. EntityAirChangeEvent is available.
Purpur does not have a dedicated SemVer release cycle tied to Paper patch versions — always verify the Purpur changelog for your build.
1---2name: events-23description: Events Skill — Purpur4---5# Events Skill — Purpur67## Purpose8Reference this skill when handling Purpur-specific events that are not available in Paper. All Paper events are also available in Purpur — this skill covers only the additional events provided by Purpur's API.910## When to Use This Skill11- Detecting when a player goes AFK or returns from AFK12- Responding to Purpur-extended entity/damage events13- Writing a plugin that specifically targets Purpur (not cross-platform)1415## API Quick Reference1617| Class / Method | Purpose | Notes |18|---------------|---------|-------|19| `PlayerAFKEvent` | Player becomes AFK | Requires `afk-timeout` set in `purpur.yml` |20| `PlayerNotAFKEvent` | Player returns from AFK | |21| `EntityAirChangeEvent` | Entity's air supply changes | Cancellable |22| `PlayerAFKEvent#getPlayer()` | `Player` going AFK | |23| `PlayerAFKEvent#isGoingAFK()` | Always `true` for AFK event | Use `PlayerNotAFKEvent` for return |2425## Code Pattern2627```java28package com.yourorg.myplugin.events;2930import org.bukkit.event.EventHandler;31import org.bukkit.event.EventPriority;32import org.bukkit.event.Listener;33import org.purpurmc.purpur.event.entity.EntityAirChangeEvent;34import org.purpurmc.purpur.event.player.PlayerAFKEvent;35import org.purpurmc.purpur.event.player.PlayerNotAFKEvent;3637import net.kyori.adventure.text.Component;38import net.kyori.adventure.text.format.NamedTextColor;39import org.bukkit.entity.Player;4041public class PurpurEventListener implements Listener {4243 // --- AFK Events ---4445 @EventHandler(priority = EventPriority.NORMAL)46 public void onPlayerAFK(PlayerAFKEvent event) {47 Player player = event.getPlayer();4849 // Notify the player50 player.sendActionBar(51 Component.text("You are now AFK.").color(NamedTextColor.GRAY)52 );5354 // Broadcast to the server55 player.getServer().broadcast(56 Component.text(player.getName() + " is now AFK.")57 .color(NamedTextColor.YELLOW)58 );59 }6061 @EventHandler(priority = EventPriority.NORMAL)62 public void onPlayerReturnFromAFK(PlayerNotAFKEvent event) {63 Player player = event.getPlayer();6465 player.sendActionBar(66 Component.text("Welcome back!").color(NamedTextColor.GREEN)67 );6869 player.getServer().broadcast(70 Component.text(player.getName() + " is no longer AFK.")71 .color(NamedTextColor.YELLOW)72 );73 }7475 // --- Entity Air Change ---7677 @EventHandler(priority = EventPriority.NORMAL)78 public void onEntityAirChange(EntityAirChangeEvent event) {79 // Example: prevent players from losing air underwater80 if (event.getEntity() instanceof Player player81 && player.hasPermission("myplugin.no-drown")) {82 event.setCancelled(true);83 }84 }85}86```8788**Guard Purpur-only registration:**89```java90// In main class onEnable — only register if running on Purpur91try {92 Class.forName("org.purpurmc.purpur.event.player.PlayerAFKEvent");93 getServer().getPluginManager().registerEvents(new PurpurEventListener(), this);94 getSLF4JLogger().info("Purpur events registered.");95} catch (ClassNotFoundException e) {96 getSLF4JLogger().info("Not running on Purpur — Purpur-specific events skipped.");97}98```99100## Common Pitfalls101102- **Registering Purpur listeners on a Paper server**: If your plugin runs on plain Paper, Purpur event classes are absent. The registration itself (calling `registerEvents`) will throw `ClassNotFoundException` at plugin load time. Always guard with a `try/catch` or `softdepend: [Purpur]` and a runtime check.103104- **Depending on AFK without configuring `purpur.yml`**: `PlayerAFKEvent` only fires if `gameplay-mechanics.afk-timeout` is set to a positive value in `purpur.yml`. With the default of `0` (disabled), the event never fires.105106- **Assuming Purpur event package paths are the same as Paper**: Purpur events are under `org.purpurmc.purpur.event.*`, NOT `io.papermc.paper.event.*`.107108## Version Notes109110- **Purpur 1.21.1**: `PlayerAFKEvent` and `PlayerNotAFKEvent` are stable. `EntityAirChangeEvent` is available.111- Purpur does not have a dedicated SemVer release cycle tied to Paper patch versions — always verify the Purpur changelog for your build.112113## Related Skills114115- [../OVERVIEW.md](../OVERVIEW.md) — Purpur platform setup116- [../../paper/events/SKILL.md](../../paper/events/SKILL.md) — All Paper events (available in Purpur too)117- [../../paper/events/player-events.md](../../paper/events/player-events.md) — Player event reference
Run npx skillmds@latest add mrpippi/events-2 in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Events Skill — Purpur It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
MrPippi (@mrpippi) published this skill. Their other Agent Skills are listed on their SkillMD profile.