225 lines
11 KiB
Java
225 lines
11 KiB
Java
package com.songoda.epicenchants.listeners;
|
|
|
|
import com.songoda.epicenchants.events.ArmorEquipEvent;
|
|
import com.songoda.epicenchants.events.HeldItemChangedEvent;
|
|
import com.songoda.epicenchants.events.HeldItemChangedEvent.EquipMethod;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.event.Event.Result;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.EventPriority;
|
|
import org.bukkit.event.Listener;
|
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
|
import org.bukkit.event.inventory.ClickType;
|
|
import org.bukkit.event.inventory.InventoryAction;
|
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
|
import org.bukkit.event.inventory.InventoryDragEvent;
|
|
import org.bukkit.event.inventory.InventoryType;
|
|
import org.bukkit.event.inventory.InventoryType.SlotType;
|
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
|
import org.bukkit.event.player.PlayerItemBreakEvent;
|
|
import org.bukkit.event.player.PlayerPickupItemEvent;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.inventory.PlayerInventory;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.OptionalInt;
|
|
import java.util.stream.IntStream;
|
|
|
|
public class HeldItemListener implements Listener {
|
|
|
|
private static final boolean SWAP_OFFHAND_SUPPORTED = Arrays.stream(ClickType.values()).anyMatch(e -> e.name().equals("SWAP_OFFHAND"));
|
|
|
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
|
public void onInvClick(InventoryClickEvent e) {
|
|
boolean shift = false, numberKey = false, swapoffhand = false;
|
|
|
|
if (e.getAction() == InventoryAction.NOTHING) {
|
|
return;
|
|
}
|
|
|
|
if (!(e.getWhoClicked() instanceof Player)) {
|
|
return;
|
|
}
|
|
|
|
if (e.getSlotType() != SlotType.ARMOR && e.getSlotType() != SlotType.QUICKBAR && e.getSlotType() != SlotType.CONTAINER) {
|
|
return;
|
|
}
|
|
|
|
if (e.getClick().equals(ClickType.SHIFT_LEFT) || e.getClick().equals(ClickType.SHIFT_RIGHT)) {
|
|
shift = true;
|
|
} else if (e.getClick().equals(ClickType.NUMBER_KEY)) {
|
|
numberKey = true;
|
|
} else if (SWAP_OFFHAND_SUPPORTED && e.getClick().equals(ClickType.valueOf("SWAP_OFFHAND"))) {
|
|
swapoffhand = true;
|
|
}
|
|
|
|
//todo offhand
|
|
Player player = (Player) e.getWhoClicked();
|
|
int heldslot = player.getInventory().getHeldItemSlot();
|
|
|
|
if (shift) {
|
|
boolean equipping;
|
|
boolean playerinv = e.getView().getTopInventory().getType() == InventoryType.CRAFTING; //only player inventory open
|
|
if (playerinv) { //items are put in the left most free
|
|
if (0 <= e.getSlot() && e.getSlot() <= 8) { //move up from hotbar
|
|
if (e.getSlot() != heldslot) //we only care about heldslot
|
|
return;
|
|
boolean slotFreeInInv = !IntStream.range(9, 36).allMatch(i -> !isAirOrNull(e.getClickedInventory().getItem(i)));
|
|
if (!slotFreeInInv) //can only move item if there is a space in inventory (assuming maxstacksize of currentItem == 1, we do not care about other items)
|
|
return;
|
|
equipping = false;
|
|
} else { //possible equipping, determine target slot
|
|
int targetslot;
|
|
boolean slotFreeInInv = !IntStream.range(9, 36).allMatch(i -> !isAirOrNull(e.getClickedInventory().getItem(i)));
|
|
boolean currentSlotInInv = 9 <= e.getSlot() && e.getSlot() <= 35;
|
|
if (!slotFreeInInv || currentSlotInInv) {
|
|
if (ArmorEquipEvent.ArmorType.matchType(e.getCurrentItem()) != null) {//we do not care about armor things here
|
|
return;
|
|
}
|
|
//shift click and no free space in inv -> moving to hotbar left most free slot
|
|
OptionalInt freehotbarslot = IntStream.range(0, 9).filter(i -> isAirOrNull(e.getClickedInventory().getItem(i))).findFirst();
|
|
if (!freehotbarslot.isPresent()) //no free slot in hotbar -> no move, no event
|
|
return;
|
|
targetslot = freehotbarslot.getAsInt();
|
|
} else {
|
|
return; //item will go to inventory not hotbar
|
|
}
|
|
if (targetslot != heldslot)
|
|
return;
|
|
equipping = true;
|
|
}
|
|
} else { //top inventory not a player inv but chest, etc
|
|
if (e.getClickedInventory() == e.getView().getBottomInventory()) {
|
|
if (e.getSlot() != heldslot) //we only care about heldslot
|
|
return;
|
|
if (e.getView().getTopInventory().firstEmpty() == -1) //top inv full
|
|
return; //nothing happens
|
|
equipping = false;
|
|
} else { //shift click in upper inv
|
|
//item will be moved to hotbar if possible, starting from right most hotbar slot
|
|
OptionalInt freehotbarslot = IntStream.range(0, 9).map(i -> 8 - i).filter(i -> isAirOrNull(e.getView().getBottomInventory().getItem(i))).findFirst();
|
|
if (!freehotbarslot.isPresent()) {
|
|
return; //will not be placed in hotbar
|
|
}
|
|
if (freehotbarslot.getAsInt() != heldslot)
|
|
return;
|
|
equipping = true;
|
|
}
|
|
}
|
|
HeldItemChangedEvent heldItemChangedEvent = new HeldItemChangedEvent((Player) e.getWhoClicked(), HeldItemChangedEvent.EquipMethod.SHIFT_CLICK, equipping ? null : e.getCurrentItem(), equipping ? e.getCurrentItem() : null);
|
|
Bukkit.getServer().getPluginManager().callEvent(heldItemChangedEvent);
|
|
if (heldItemChangedEvent.isCancelled()) {
|
|
e.setCancelled(true);
|
|
}
|
|
} else {
|
|
ItemStack newItem = e.getCursor();
|
|
ItemStack oldItem = e.getCurrentItem();
|
|
EquipMethod method;
|
|
if (numberKey) {
|
|
if (!(e.getClickedInventory() instanceof PlayerInventory)
|
|
|| e.getHotbarButton() != heldslot) //we only care about heldslot
|
|
return;
|
|
method = EquipMethod.HOTBAR_SWAP;
|
|
newItem = e.getCurrentItem();
|
|
oldItem = e.getClickedInventory().getItem(e.getHotbarButton());
|
|
} else if (swapoffhand) {
|
|
if (!(e.getClickedInventory() instanceof PlayerInventory)
|
|
|| e.getSlot() != heldslot) //we only care about heldslot
|
|
return;
|
|
method = EquipMethod.OFFHAND_SWAP;
|
|
newItem = e.getClickedInventory().getItem(40);
|
|
oldItem = e.getCurrentItem();
|
|
} else {
|
|
if (!(e.getClickedInventory() instanceof PlayerInventory)
|
|
|| e.getSlot() != heldslot) //we only care about heldslot
|
|
return;
|
|
method = EquipMethod.PICK_DROP;
|
|
}
|
|
HeldItemChangedEvent heldItemChangedEvent = new HeldItemChangedEvent((Player) e.getWhoClicked(), method, oldItem, newItem);
|
|
Bukkit.getServer().getPluginManager().callEvent(heldItemChangedEvent);
|
|
if (heldItemChangedEvent.isCancelled()) {
|
|
e.setCancelled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void inventoryDrag(InventoryDragEvent event) {
|
|
if (event.getRawSlots().isEmpty())
|
|
return;
|
|
|
|
int rawslot = event.getRawSlots().stream().findFirst().orElse(0);
|
|
int invslot = event.getView().convertSlot(rawslot);
|
|
boolean bottominventory = rawslot != invslot;
|
|
|
|
if (bottominventory && event.getWhoClicked().getInventory().getHeldItemSlot() == invslot) {
|
|
HeldItemChangedEvent heldItemChangedEvent = new HeldItemChangedEvent((Player) event.getWhoClicked(), EquipMethod.DRAG, null, event.getOldCursor());
|
|
Bukkit.getServer().getPluginManager().callEvent(heldItemChangedEvent);
|
|
if (heldItemChangedEvent.isCancelled()) {
|
|
event.setResult(Result.DENY);
|
|
event.setCancelled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void itemBreakEvent(PlayerItemBreakEvent e) {
|
|
Player p = e.getPlayer();
|
|
PlayerInventory inv = p.getInventory();
|
|
|
|
//find in hotbar
|
|
int hotbarslot = -1;
|
|
ItemStack broken = inv.getItem(inv.getHeldItemSlot());
|
|
if (!isAirOrNull(broken) && broken.equals(e.getBrokenItem()))
|
|
hotbarslot = inv.getHeldItemSlot();
|
|
|
|
if (hotbarslot != -1) {
|
|
HeldItemChangedEvent heldItemChangedEvent = new HeldItemChangedEvent(p, EquipMethod.BROKE, e.getBrokenItem(), null);
|
|
Bukkit.getServer().getPluginManager().callEvent(heldItemChangedEvent);
|
|
if (heldItemChangedEvent.isCancelled()) {
|
|
ItemStack i = e.getBrokenItem().clone();
|
|
i.setAmount(1);
|
|
i.setDurability((short) (i.getDurability() - 1));
|
|
p.getInventory().setItem(hotbarslot, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
@EventHandler
|
|
public void playerDeathEvent(PlayerDeathEvent event) {
|
|
ItemStack i = event.getEntity().getInventory().getItem(event.getEntity().getInventory().getHeldItemSlot());
|
|
if (!isAirOrNull(i))
|
|
Bukkit.getServer().getPluginManager().callEvent(new HeldItemChangedEvent(event.getEntity(), EquipMethod.DEATH, i, null));
|
|
// No way to cancel a death event.
|
|
}
|
|
|
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
|
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
|
//there is no clear way to determine whether the player pressed Q or dropped the item from and inventory view,
|
|
//as Player.getOpenInventory().getType will always return CRAFTING whether the player has open their invntory or not
|
|
//we try to make a best efford solution
|
|
//when the item in the held slot is null we assume it was dropped by pressing Q
|
|
if (isAirOrNull(event.getPlayer().getInventory().getItem(event.getPlayer().getInventory().getHeldItemSlot())))
|
|
Bukkit.getServer().getPluginManager().callEvent(new HeldItemChangedEvent(event.getPlayer(), EquipMethod.DROP_ITEM, event.getItemDrop().getItemStack(), null));
|
|
}
|
|
|
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
|
public void onPlayerPickUpItem(PlayerPickupItemEvent event) {
|
|
if (event.getItem().getItemStack().getMaxStackSize() == 1) { //tools maxStackSize is 1, ignore other items
|
|
int firstEmpty = event.getPlayer().getInventory().firstEmpty();
|
|
if (0 <= firstEmpty && firstEmpty <= 8
|
|
&& event.getPlayer().getInventory().getHeldItemSlot() == firstEmpty)
|
|
Bukkit.getServer().getPluginManager().callEvent(new HeldItemChangedEvent(event.getPlayer(), EquipMethod.PICKUP_ITEM, null, event.getItem().getItemStack()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A utility method to support versions that use null or air ItemStacks.
|
|
*/
|
|
private boolean isAirOrNull(ItemStack item) {
|
|
return item == null || item.getType().equals(Material.AIR);
|
|
}
|
|
}
|