EpicEnchants/src/main/java/com/songoda/epicenchants/listeners/HeldItemListener.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);
}
}