From 73600b72b6d5ba282ba3c48d6d5f2164234b23d9 Mon Sep 17 00:00:00 2001
From: Rodney <36546810+RodneyMKay@users.noreply.github.com>
Date: Tue, 22 Aug 2023 07:22:05 +0200
Subject: [PATCH] Add PlayerPickItemEvent (#5590)

---
 patches/api/Add-PlayerPickItemEvent.patch    | 103 +++++++++++++++++++
 patches/server/Add-PlayerPickItemEvent.patch |  45 ++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 patches/api/Add-PlayerPickItemEvent.patch
 create mode 100644 patches/server/Add-PlayerPickItemEvent.patch

diff --git a/patches/api/Add-PlayerPickItemEvent.patch b/patches/api/Add-PlayerPickItemEvent.patch
new file mode 100644
index 0000000000..8ab9a1014a
--- /dev/null
+++ b/patches/api/Add-PlayerPickItemEvent.patch
@@ -0,0 +1,103 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com>
+Date: Wed, 8 Sep 2021 22:15:43 +0200
+Subject: [PATCH] Add PlayerPickItemEvent
+
+
+diff --git a/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java b/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/event/player/PlayerPickItemEvent.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.event.player;
++
++import org.apache.commons.lang3.Validate;
++import org.bukkit.entity.Player;
++import org.bukkit.event.Cancellable;
++import org.bukkit.event.HandlerList;
++import org.bukkit.event.player.PlayerEvent;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Range;
++
++/**
++ * Event that is fired when a player uses the pick item functionality (middle-clicking a block to get the appropriate
++ * item). However, note that this event will only trigger if an item has to be moved from the inventory to the hotbar.
++ * After the handling of this event, the contents of the source and the target slot will be swapped and the currently
++ * selected hotbar slot of the player will be set to the target slot.
++ * <p>
++ * Note: This event will not be fired for players in creative mode.
++ */
++public class PlayerPickItemEvent extends PlayerEvent implements Cancellable {
++    private static final HandlerList HANDLER_LIST = new HandlerList();
++    private int targetSlot;
++    private int sourceSlot;
++    private boolean cancelled;
++
++    public PlayerPickItemEvent(@NotNull Player player, int targetSlot, int sourceSlot) {
++        super(player);
++        this.targetSlot = targetSlot;
++        this.sourceSlot = sourceSlot;
++    }
++
++    /**
++     * Returns the slot the item that is being picked goes into.
++     *
++     * @return hotbar slot (0-8 inclusive)
++     */
++    @Range(from = 0, to = 8)
++    public int getTargetSlot() {
++        return this.targetSlot;
++    }
++
++    /**
++     * Changes the slot the item that is being picked goes into.
++     *
++     * @param targetSlot hotbar slot (0-8 inclusive)
++     */
++    public void setTargetSlot(@Range(from = 0, to = 8) int targetSlot) {
++        Validate.isTrue(targetSlot >= 0 && targetSlot <= 8, "Target slot must be in range 0 - 8 (inclusive)");
++        this.targetSlot = targetSlot;
++    }
++
++    /**
++     * Returns the slot in which the item that will be put into the players hotbar is located.
++     *
++     * @return player inventory slot (0-35 inclusive)
++     */
++    @Range(from = 0, to = 35)
++    public int getSourceSlot() {
++        return this.sourceSlot;
++    }
++
++    /**
++     * Change the source slot from which the item that will be put in the players hotbar will be taken.
++     *
++     * @param sourceSlot player inventory slot (0-35 inclusive)
++     */
++    public void setSourceSlot(@Range(from = 0, to = 35) int sourceSlot) {
++        Validate.isTrue(sourceSlot >= 0 && sourceSlot <= 35, "Source slot must be in range of the players inventorys slot ids");
++        this.sourceSlot = sourceSlot;
++    }
++
++    @Override
++    public boolean isCancelled() {
++        return this.cancelled;
++    }
++
++    @Override
++    public void setCancelled(boolean cancel) {
++        this.cancelled = cancel;
++    }
++
++    @NotNull
++    @Override
++    public HandlerList getHandlers() {
++        return HANDLER_LIST;
++    }
++
++    @NotNull
++    public static HandlerList getHandlerList() {
++        return HANDLER_LIST;
++    }
++}
diff --git a/patches/server/Add-PlayerPickItemEvent.patch b/patches/server/Add-PlayerPickItemEvent.patch
new file mode 100644
index 0000000000..8941a289b3
--- /dev/null
+++ b/patches/server/Add-PlayerPickItemEvent.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: RodneyMKay <36546810+RodneyMKay@users.noreply.github.com>
+Date: Wed, 8 Sep 2021 21:34:01 +0200
+Subject: [PATCH] Add PlayerPickItemEvent
+
+
+diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+             this.disconnect("Invalid hotbar selection (Hacking?)", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause
+             return;
+         }
+-        this.player.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed
++        Player bukkitPlayer = this.player.getBukkitEntity();
++        int targetSlot = this.player.getInventory().getSuitableHotbarSlot();
++        int sourceSlot = packet.getSlot();
++
++        io.papermc.paper.event.player.PlayerPickItemEvent event = new io.papermc.paper.event.player.PlayerPickItemEvent(bukkitPlayer, targetSlot, sourceSlot);
++        if (!event.callEvent()) return;
++
++        this.player.getInventory().pickSlot(event.getSourceSlot(), event.getTargetSlot());
+         // Paper end
+         this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, this.player.getInventory().selected, this.player.getInventory().getItem(this.player.getInventory().selected)));
+         this.player.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, packet.getSlot(), this.player.getInventory().getItem(packet.getSlot())));
+diff --git a/src/main/java/net/minecraft/world/entity/player/Inventory.java b/src/main/java/net/minecraft/world/entity/player/Inventory.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/world/entity/player/Inventory.java
++++ b/src/main/java/net/minecraft/world/entity/player/Inventory.java
+@@ -0,0 +0,0 @@ public class Inventory implements Container, Nameable {
+     }
+ 
+     public void pickSlot(int slot) {
+-        this.selected = this.getSuitableHotbarSlot();
++        // Paper start - Add PlayerPickItemEvent
++        pickSlot(slot, this.getSuitableHotbarSlot());
++    }
++
++    public void pickSlot(int slot, int targetSlot) {
++        this.selected = targetSlot;
++        // Paper end
+         ItemStack itemstack = (ItemStack) this.items.get(this.selected);
+ 
+         this.items.set(this.selected, (ItemStack) this.items.get(slot));