Skip to content
Open
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
@@ -0,0 +1,141 @@
package io.papermc.paper.event.inventory;

import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

/**
* Called when a {@link Player} selects an item inside a bundle.
* <p>
* NOTE: This event does not fire for bundle item selections in creative mode player inventories.
*/
@NullMarked
public final class PlayerBundleItemSelectEvent extends InventoryEvent {

private static final HandlerList HANDLER_LIST = new HandlerList();

private final ItemStack bundle;
private final int rawSlot;
private final int slot;

private final ItemStack previousItem;
private final ItemStack selectedItem;

private final int previousIndex;
private final int selectedIndex;
private final int direction;

@ApiStatus.Internal
public PlayerBundleItemSelectEvent(final InventoryView view, final ItemStack bundle, final int rawSlot, final ItemStack previousItem, final ItemStack selectedItem, final int previousIndex, final int selectedIndex, final int direction) {
super(view);

this.bundle = bundle;
this.rawSlot = rawSlot;
this.slot = view.convertSlot(rawSlot);

this.previousItem = previousItem;
this.selectedItem = selectedItem;

this.previousIndex = previousIndex;
this.selectedIndex = selectedIndex;
this.direction = direction;
}

/**
* Gets the player who triggered the event.
*
* @return the player
*/
public Player getPlayer() {
return (Player) this.getView().getPlayer();
}

/**
* Gets the bundle item.
*
* @return the bundle item
*/
public ItemStack getBundle() {
return this.bundle;
}

/**
* Gets the slot number of the bundle, depending on which {@link Inventory} it is located in.
*
* @return the slot number
* @see InventoryClickEvent#getSlot()
*/
public int getSlot() {
return this.slot;
}

/**
* Gets the raw slot number of the bundle inside the {@link InventoryView}.
*
* @return the raw slot number
* @see InventoryClickEvent#getRawSlot()
*/
public int getRawSlot() {
return this.rawSlot;
}

/**
* Gets the previously selected item inside the bundle. If no item was previously selected, this will return an empty item.

* @return the previously selected item
*/
public ItemStack getPreviousItem() {
return this.previousItem.clone();
}

/**
* Gets the selected item inside the bundle.
*
* @return the selected item
*/
public ItemStack getSelectedItem() {
return this.selectedItem.clone();
}

/**
* Gets the previously selected index. If no item was previously selected, this will be -1.
*
* @return the previously selected index
*/
public int getPreviousIndex() {
return this.previousIndex;
}

/**
* Gets the selected index.
*
* @return the selected index
*/
public int getSelectedIndex() {
return this.selectedIndex;
}

/**
* Gets the direction from the previous selection to the new one.
*
* @return +1 if forwards, -1 if backwards
*/
public int getDirection() {
return this.direction;
}

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

public static HandlerList getHandlerList() {
return HANDLER_LIST;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,14 @@
}

@Override
@@ -572,6 +_,7 @@
@@ -566,12 +_,14 @@
@Override
public void handleBundleItemSelectedPacket(final ServerboundSelectBundleItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
+ CraftEventFactory.callPlayerBundleItemSelectEvent(this.player, packet.slotId(), packet.selectedItemIndex()); // Paper - PlayerBundleItemSelectEvent
this.player.containerMenu.setSelectedBundleItemIndex(packet.slotId(), packet.selectedItemIndex());
}

@Override
public void handleRecipeBookChangeSettingsPacket(final ServerboundRecipeBookChangeSettingsPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,56 @@ public static BlockIgniteEvent callBlockIgniteEvent(Level level, BlockPos pos, I
return event;
}

public static void callPlayerBundleItemSelectEvent(final net.minecraft.world.entity.player.Player player, final int slotId, final int selectedIndex) {
if (player.isCreative() && player.containerMenu instanceof net.minecraft.world.inventory.InventoryMenu) {
// The packet's slotId will always be 0 if this packet is sent for a player selecting an item in a bundle in their creative inventory,
// making it unfit for firing an event.
return;
}

if (slotId < 0 || slotId >= player.containerMenu.slots.size() || selectedIndex <= net.minecraft.world.item.component.BundleContents.NO_SELECTED_ITEM_INDEX) {
return;
}

final net.minecraft.world.item.ItemStack item = player.containerMenu.slots.get(slotId).getItem();
if (!item.is(net.minecraft.tags.ItemTags.BUNDLES)) {
return;
}

final net.minecraft.world.item.component.BundleContents contents = item.get(net.minecraft.core.component.DataComponents.BUNDLE_CONTENTS);
if (contents == null) {
return;
}

final int previousIndex = contents.getSelectedItemIndex();
if (selectedIndex >= contents.size() || selectedIndex == previousIndex) {
return;
}

int direction;
if (previousIndex == -1) {
direction = selectedIndex == 0 ? 1 : -1;
} else {
int diff = selectedIndex - previousIndex;
direction = diff > 0 ? 1 : -1;

if (Math.abs(diff) == contents.size() - 1) {
direction = -direction;
}
}

new io.papermc.paper.event.inventory.PlayerBundleItemSelectEvent(
player.containerMenu.getBukkitView(),
item.asBukkitMirror(),
slotId,
contents.getSelectedItem() != null ? contents.getSelectedItem().create().asBukkitMirror() : org.bukkit.inventory.ItemStack.empty(),
contents.items().get(selectedIndex).create().asBukkitMirror(),
previousIndex,
selectedIndex,
direction
).callEvent();
}

public static void handleInventoryCloseEvent(net.minecraft.world.entity.player.Player human, org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
InventoryCloseEvent event = new InventoryCloseEvent(human.containerMenu.getBukkitView(), reason); // Paper
human.level().getCraftServer().getPluginManager().callEvent(event);
Expand Down