Astral Realms Documentation Help

Events

AstralItems fires six custom Bukkit events that other plugins (and AstralItems' own heads) can listen to.

HandEquipEvent

Fully qualified name: com.astralrealms.items.event.HandEquipEvent (extends PlayerEvent).

Fired by HandListener whenever the main hand's ItemStack changes in a way the plugin cares about:

Trigger

Source

oldItem

newItem

Main-hand slot updated

EntityEquipmentChangedEvent

Previous main-hand item

New main-hand item

Interaction with item frame / armour stand

PlayerInteractAtEntityEvent

Current main-hand item

Empty ItemStack (sentinel)

Player quits

PlayerQuitEvent

Current main-hand item

Empty ItemStack (sentinel)

The event is not cancellable — it is a notification. Both oldItem and newItem are defensively cloned on construction.

Fields

Field

Type

Description

player

Player

Inherited from PlayerEvent.

oldItem

ItemStack

The item leaving the slot (cloned).

newItem

ItemStack

The item entering the slot (cloned).

Example listener

import com.astralrealms.items.event.HandEquipEvent; import com.astralrealms.items.AstralItems; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class MyEquipListener implements Listener { @EventHandler public void onEquip(HandEquipEvent event) { AstralItems plugin = AstralItems.get(); plugin.items().fromItemStack(event.newItem()).ifPresent(instance -> getLogger().info(event.getPlayer().getName() + " equipped " + instance.blueprint().id()) ); } }

ItemHoldEvent

Fully qualified name: com.astralrealms.items.event.hand.ItemHoldEvent (extends PlayerEvent).

Fired by HoldListener off Paper's EntityEquipmentChangedEvent when a non-empty item enters a player's main hand. Not cancellable — it is a notification. Drives the hold-item pipeline head.

EntityEquipmentChangedEvent also fires when the same item is merely updated in place — durability ticking down while mining, a lore rewrite — and those are filtered out, so a hold pipeline does not re-run on every hit. Sameness is decided by the item's identity rather than by its meta: two custom items match on their ItemInstance unique id when either has one, otherwise on their blueprint id; two vanilla items must be the same material and similar stacks.

Fields

Field

Type

Description

player

Player

Inherited from PlayerEvent.

itemStack

ItemStack

The item that entered the hand (itemStack()).

slot

EquipmentSlot

Always HAND (slot()).

Example listener

@EventHandler public void onHold(ItemHoldEvent event) { AstralItems.get().items().fromItemStack(event.itemStack()).ifPresent(instance -> event.getPlayer().sendMessage("Now holding " + instance.blueprint().id()) ); }

ItemUnholdEvent

Fully qualified name: com.astralrealms.items.event.hand.ItemUnholdEvent (extends PlayerEvent).

The counterpart to ItemHoldEvent: fired by HoldListener when a non-empty item leaves a player's main hand. Not cancellable. Drives the unhold-item pipeline head.

It is also fired from PlayerQuitEvent for whatever the player was holding, because equipment changes do not fire on disconnect — without it a held item would never be released and anything the hold pipeline applied would leak past the session.

Fields

Field

Type

Description

player

Player

Inherited from PlayerEvent.

itemStack

ItemStack

The item that left the hand (itemStack()).

slot

EquipmentSlot

Always HAND (slot()).

ArmorEquipEvent

Fully qualified name: com.astralrealms.items.event.armor.ArmorEquipEvent (extends PlayerEvent).

Fired by ArmorListener off Paper's PlayerArmorChangeEvent whenever a non-empty item enters an armour slot. Not cancellable — it is a notification. Drives the equip-armor pipeline head.

Fields

Field

Type

Description

player

Player

Inherited from PlayerEvent.

itemStack

ItemStack

The item that was equipped (getItemStack()).

slot

EquipmentSlot

The armour slot it entered (getSlot()).

ArmorUnEquipEvent

Fully qualified name: com.astralrealms.items.event.armor.ArmorUnEquipEvent (extends PlayerEvent).

The counterpart to ArmorEquipEvent: fired by ArmorListener when a non-empty item leaves an armour slot. Not cancellable. Drives the unequip-armor pipeline head.

Fields

Field

Type

Description

player

Player

Inherited from PlayerEvent.

itemStack

ItemStack

The item that was removed (getItemStack()).

slot

EquipmentSlot

The armour slot it left (getSlot()).

AnvilResultEvent

Fully qualified name: com.astralrealms.items.event.AnvilResultEvent (extends PlayerEvent, implements Cancellable).

Fired by AnvilService every time the player's custom anvil result needs to be recomputed: when an input slot changes, when the rename text changes, or when a click happens. Listeners can override the result item, override the level cost, or cancel the whole combine.

The rule pipeline — CustomItemRule → EnchantedBookRule → VanillaAnvilRule — runs before the event fires, and exactly one rule claims every operation, so listeners always see a populated result and cost (or a cancelled event) and can either tweak or fully replace them.

Fields

Field

Type

Description

player

Player

The anvil user.

session

AnvilSession

The full session — exposes both input slots, the output slot, the cursor stack, and the rename text.

inputLeft

ItemStack

Slot 0. Cloned snapshot — mutating it has no effect.

inputRight

ItemStack

Slot 1. Cloned snapshot — mutating it has no effect.

result

ItemStack

Slot 2. Replace it with event.result(newStack) to change the output. null/ empty / cancelled = no result.

cost

int

Level cost the player will pay on take. Set to 0 to make the result free. The server refuses a take at cost >= 1500 (NmsAnvilLogic.MAX_ANVIL_COST) outside creative, regardless of what a listener sets.

materialCost

int

How many items to consume from the right slot on take. 0 (the default) consumes the whole slot; a positive value consumes only that many, as material-based repair does.

Example listener

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onAnvilResult(AnvilResultEvent event) { ItemStack right = event.inputRight(); if (right.getType() != Material.NETHER_STAR) return; // Custom recipe: any item + nether star = item with custom-model-data 9999 ItemStack result = event.inputLeft().clone(); result.editMeta(meta -> meta.setCustomModelData(9999)); event.result(result); event.cost(10); }

The plugin's own rules no longer run as event listeners — AnvilListener only routes players into the anvil and forwards session lifecycle events. Enchanted-book combines that respect metadata.available-enchantments, the over-cap book rejection, and the vanilla fallback all live in the rule pipeline that runs ahead of this event. See Anvil for the full recompute pipeline.

Reacting to a Bukkit event from inside a pipeline

The equip-hand head subscribes to HandEquipEvent for you — wiring a HandEquipPipelineHead in a blueprint is enough to run a pipeline whenever the item is equipped:

pipelines: on-equip: head: type: equip-hand links: welcome: type: execute-actions actions: - "[message] <gold>You equipped %item_name%</gold>"

For every other Bukkit event the plugin already hooks (block break, entity damage, fishing, drag-and-drop, …), use the corresponding head from Pipeline Heads — there is no need to write your own Bukkit listener.

Last modified: 03 September 2026