Skip to content

Add EntityEquipmentChangedEvent #12011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
Expand All @@ -16,8 +17,10 @@
* Called when the player themselves change their armor items
* <p>
* Not currently called for environmental factors though it <strong>MAY BE IN THE FUTURE</strong>
* @apiNote Use {@link io.papermc.paper.event.entity.EntityEquipmentChangedEvent} for all entity equipment changes
*/
@NullMarked
@ApiStatus.Obsolete(since = "1.21.4")
public class PlayerArmorChangeEvent extends PlayerEvent {

private static final HandlerList HANDLER_LIST = new HandlerList();
Expand All @@ -38,11 +41,27 @@ public PlayerArmorChangeEvent(final Player player, final SlotType slotType, fina
* Gets the type of slot being altered.
*
* @return type of slot being altered
* @deprecated {@link SlotType} does not accurately represent what item types are valid in each slot. Use {@link #getSlot()} instead.
*/
@Deprecated(since = "1.21.4")
public SlotType getSlotType() {
return this.slotType;
}

/**
* Gets the slot being altered.
*
* @return slot being altered
*/
public EquipmentSlot getSlot() {
return switch (this.slotType) {
case HEAD -> EquipmentSlot.HEAD;
case CHEST -> EquipmentSlot.CHEST;
case LEGS -> EquipmentSlot.LEGS;
case FEET -> EquipmentSlot.FEET;
};
}

/**
* Gets the existing item that's being replaced
*
Expand Down Expand Up @@ -70,6 +89,10 @@ public static HandlerList getHandlerList() {
return HANDLER_LIST;
}

/**
* @deprecated {@link SlotType} does not accurately represent what item types are valid in each slot.
*/
@Deprecated(since = "1.21.4")
public enum SlotType {
HEAD(NETHERITE_HELMET, DIAMOND_HELMET, GOLDEN_HELMET, IRON_HELMET, CHAINMAIL_HELMET, LEATHER_HELMET, CARVED_PUMPKIN, PLAYER_HEAD, SKELETON_SKULL, ZOMBIE_HEAD, CREEPER_HEAD, WITHER_SKELETON_SKULL, TURTLE_HELMET, DRAGON_HEAD, PIGLIN_HEAD),
CHEST(NETHERITE_CHESTPLATE, DIAMOND_CHESTPLATE, GOLDEN_CHESTPLATE, IRON_CHESTPLATE, CHAINMAIL_CHESTPLATE, LEATHER_CHESTPLATE, ELYTRA),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.papermc.paper.event.entity;

import java.util.Collections;
import java.util.Map;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Unmodifiable;
import org.jspecify.annotations.NullMarked;

/**
* Called whenever a change to an entity's equipment has been detected. This event is called after effects from
* attribute modifiers and enchantments have been updated.
* <p>
* Examples of actions that can trigger this event:
* <ul>
* <li>An entity being added to a world.</li>
* <li>A player logging in.</li>
* <li>The durability of an equipment item changing.</li>
* <li>A dispenser equipping an item onto an entity.</li>
* <li>An entity picking up an armor or weapon item from the ground.</li>
* <li>A player changing their equipped armor.</li>
* <li>A player changes their currently held item.</li>
* </ul>
*/
@NullMarked
public class EntityEquipmentChangedEvent extends EntityEvent {

private static final HandlerList HANDLER_LIST = new HandlerList();

private final Map<EquipmentSlot, EquipmentChange> equipmentChanges;

@ApiStatus.Internal
public EntityEquipmentChangedEvent(final LivingEntity entity, final Map<EquipmentSlot, EquipmentChange> equipmentChanges) {
super(entity);

this.equipmentChanges = equipmentChanges;
}

@Override
public LivingEntity getEntity() {
return (LivingEntity) this.entity;
}

/**
* Gets a map of changed slots to their respective equipment changes.
*
* @return the equipment changes map
*/
public @Unmodifiable Map<EquipmentSlot, EquipmentChange> getEquipmentChanges() {
return Collections.unmodifiableMap(this.equipmentChanges);
}

@Override
public HandlerList getHandlers() {
return HANDLER_LIST;
}

public static HandlerList getHandlerList() {
return HANDLER_LIST;
}

/**
* Represents a change in equipment for a single equipment slot.
*/
@ApiStatus.NonExtendable
public interface EquipmentChange {

/**
* Gets the existing item that is being replaced.
*
* @return the existing item
*/
@Contract(pure = true, value = "-> new")
ItemStack oldItem();

/**
* Gets the new item that is replacing the existing item.
*
* @return the new item
*/
@Contract(pure = true, value = "-> new")
ItemStack newItem();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1336,20 +1336,57 @@
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
if (map != null) {
this.handleHandSwap(map);
@@ -2595,6 +_,13 @@
@@ -2586,6 +_,20 @@
@Nullable
private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
Map<EquipmentSlot, ItemStack> map = null;
+ // Paper start - EntityEquipmentChangedEvent
+ record EquipmentChangeImpl(org.bukkit.inventory.ItemStack oldItem, org.bukkit.inventory.ItemStack newItem) implements io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange {
+ @Override
+ public org.bukkit.inventory.ItemStack oldItem() {
+ return this.oldItem.clone();
+ }
+
+ @Override
+ public org.bukkit.inventory.ItemStack newItem() {
+ return this.newItem.clone();
+ }
+ }
+ Map<org.bukkit.inventory.EquipmentSlot, io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange> equipmentChanges = null;
+ // Paper end - EntityEquipmentChangedEvent

for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) {
ItemStack itemStack = switch (equipmentSlot.getType()) {
@@ -2595,11 +_,20 @@
};
ItemStack itemBySlot = this.getItemBySlot(equipmentSlot);
if (this.equipmentHasChanged(itemStack, itemBySlot)) {
+ // Paper start - PlayerArmorChangeEvent
+ // Paper start - EntityEquipmentChangedEvent, PlayerArmorChangeEvent
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemStack);
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemBySlot);
+ if (this instanceof ServerPlayer && equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemStack);
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemBySlot);
+ new com.destroystokyo.paper.event.player.PlayerArmorChangeEvent((org.bukkit.entity.Player) this.getBukkitEntity(), com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType.valueOf(equipmentSlot.name()), oldItem, newItem).callEvent();
+ }
+ // Paper end - PlayerArmorChangeEvent
+ // Paper end - EntityEquipmentChangedEvent, PlayerArmorChangeEvent
if (map == null) {
map = Maps.newEnumMap(EquipmentSlot.class);
+ equipmentChanges = Maps.newEnumMap(org.bukkit.inventory.EquipmentSlot.class); // Paper - EntityEquipmentChangedEvent
}

map.put(equipmentSlot, itemBySlot);
+ equipmentChanges.put(org.bukkit.craftbukkit.CraftEquipmentSlot.getSlot(equipmentSlot), new EquipmentChangeImpl(oldItem, newItem)); // Paper - EntityEquipmentChangedEvent
AttributeMap attributes = this.getAttributes();
if (!itemStack.isEmpty()) {
this.stopLocationBasedEffects(itemStack, equipmentSlot, attributes);
@@ -2624,6 +_,8 @@
}
}
}
+
+ new io.papermc.paper.event.entity.EntityEquipmentChangedEvent(this.getBukkitLivingEntity(), equipmentChanges).callEvent(); // Paper - EntityEquipmentChangedEvent
}

return map;
@@ -2664,7 +_,7 @@
this.lastBodyItemStack = itemStack;
}
Expand Down
Loading