I’m writing a Bukkit/Spigot plugin that opens a custom Inventory as a GUI for players. In this GUI I have two special slots defined in GuiUtils:
My current attempt cancels clicks and drags on that slot, but a clever player can still shift-click a stack into it, immediately shift it back out on the next tick, or drag to the cursor and back.
Here’s a simplified version of my listener:
EventHandler
public void onInventoryClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
Player player = (Player) e.getWhoClicked();
UUID uuid = player.getUniqueId();
// If this player isn’t using our GUI, ignore
if (!plugin.isUsingGui(uuid)) return;
Inventory gui = plugin.getPlayerGui(uuid);
if (gui == null || e.getClickedInventory() != gui) return;
int slot = e.getSlot();
// Attempt to block all placement into COIN_SLOT
if (slot == GuiUtils.COIN_SLOT) {
e.setCancelled(true);
return;
}
// Other GUI logic...
}
I also cancel InventoryDragEvent for that slot:
EventHandler
public void onInventoryDrag(InventoryDragEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
UUID uuid = ((Player)e.getWhoClicked()).getUniqueId();
if (!plugin.isUsingGui(uuid)) return;
Inventory gui = plugin.getPlayerGui(uuid);
if (gui == null) return;
// Cancel any drag placing items into COIN_SLOT
for (int rawSlot : e.getRawSlots()) {
if (rawSlot == GuiUtils.COIN_SLOT) {
e.setCancelled(true);
return;
}
}
}
Despite this, players can still sneak in items via shift-click from their inventory, or by quickly placing and picking them back up.
What I’ve tried
No matter what the player does—shift-click, double-click, drag, number-key swap—they must never be able to place any item into COIN_SLOT. Ideally, the slot should function identically to the output slot of a crafting table: you can take items out, but you can never put anything in.
- PAPER_SLOT – players may insert paper here
- COIN_SLOT – players may remove coins here
My current attempt cancels clicks and drags on that slot, but a clever player can still shift-click a stack into it, immediately shift it back out on the next tick, or drag to the cursor and back.
Here’s a simplified version of my listener:
EventHandler
public void onInventoryClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
Player player = (Player) e.getWhoClicked();
UUID uuid = player.getUniqueId();
// If this player isn’t using our GUI, ignore
if (!plugin.isUsingGui(uuid)) return;
Inventory gui = plugin.getPlayerGui(uuid);
if (gui == null || e.getClickedInventory() != gui) return;
int slot = e.getSlot();
// Attempt to block all placement into COIN_SLOT
if (slot == GuiUtils.COIN_SLOT) {
e.setCancelled(true);
return;
}
// Other GUI logic...
}
I also cancel InventoryDragEvent for that slot:
EventHandler
public void onInventoryDrag(InventoryDragEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
UUID uuid = ((Player)e.getWhoClicked()).getUniqueId();
if (!plugin.isUsingGui(uuid)) return;
Inventory gui = plugin.getPlayerGui(uuid);
if (gui == null) return;
// Cancel any drag placing items into COIN_SLOT
for (int rawSlot : e.getRawSlots()) {
if (rawSlot == GuiUtils.COIN_SLOT) {
e.setCancelled(true);
return;
}
}
}
Despite this, players can still sneak in items via shift-click from their inventory, or by quickly placing and picking them back up.
What I’ve tried
- Cancelling InventoryClickEvent for MOVE_TO_OTHER_INVENTORY actions
- Cancelling DOUBLE_CLICK when the clicked slot is COIN_SLOT
- Cancelling drags (as shown above)
- Listening to InventoryCloseEvent and cleaning up… but that only runs after the fact
No matter what the player does—shift-click, double-click, drag, number-key swap—they must never be able to place any item into COIN_SLOT. Ideally, the slot should function identically to the output slot of a crafting table: you can take items out, but you can never put anything in.
- Type
- Requesting
- Provided by
- Individual
