package tc.oc.pgm.kits; import java.util.Iterator; import java.util.Objects; import javax.annotation.Nullable; import javax.inject.Inject; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.entity.HumanEntity; 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.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCreativeEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.inventory.ItemStack; import tc.oc.commons.bukkit.inventory.Slot; import tc.oc.pgm.events.ItemTransferEvent; import tc.oc.pgm.events.ListenerScope; import tc.oc.pgm.kits.tag.ItemTags; import tc.oc.pgm.match.MatchPlayerFinder; import tc.oc.pgm.match.MatchScope; @ListenerScope(MatchScope.LOADED) public class ItemSharingAndLockingListener implements Listener { private final MatchPlayerFinder playerFinder; @Inject private ItemSharingAndLockingListener(MatchPlayerFinder playerFinder) { this.playerFinder = playerFinder; } private boolean isLocked(@Nullable ItemStack item) { return item != null && ItemTags.LOCKED.get(item); } private boolean isUnshareable(@Nullable ItemStack item) { return item != null && (isLocked(item) || ItemTags.PREVENT_SHARING.get(item)); } private void sendLockWarning(HumanEntity player) { playerFinder.player(player).ifPresent( mp -> mp.sendWarning(new TranslatableComponent("item.locked"), true) ); } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onInventoryClick(final InventoryClickEvent event) { if(event instanceof InventoryCreativeEvent) return;; // Ensure the player is clicking in their own inventory // TODO: should we allow items to be locked into other types of inventories? if(!Objects.equals(event.getWhoClicked(), event.getInventory().getHolder())) return; // Break out of the switch if the action will move a locked item, otherwise return switch(event.getAction()) { case HOTBAR_SWAP: case HOTBAR_MOVE_AND_READD: // These actions can move up to two stacks. Check the hotbar stack, // and then fall through to check the stack under the cursor. if(isLocked(Slot.Hotbar.forPosition(event.getHotbarButton()) .getItem(event.getWhoClicked().getInventory()))) break; // fall through case PICKUP_ALL: case PICKUP_HALF: case PICKUP_SOME: case PICKUP_ONE: case SWAP_WITH_CURSOR: case MOVE_TO_OTHER_INVENTORY: case DROP_ONE_SLOT: case DROP_ALL_SLOT: case COLLECT_TO_CURSOR: // All these actions move only a single stack, except COLLECT_TO_CURSOR, // which can only move items that are stackable with the one under the cursor, // and locked items are only stackable with other locked items. if(isLocked(event.getCurrentItem())) break; // fall through default: return; } event.setCancelled(true); sendLockWarning(event.getWhoClicked()); } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onDropItem(PlayerDropItemEvent event) { if(isLocked(event.getItemDrop().getItemStack())) { event.setCancelled(true); sendLockWarning(event.getPlayer()); } else if(isUnshareable(event.getItemDrop().getItemStack())) { event.getItemDrop().remove(); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onTransferItem(ItemTransferEvent event) { if(event.getType() == ItemTransferEvent.Type.PLACE && isUnshareable(event.getItemStack())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onDeath(PlayerDeathEvent event) { for(Iterator<ItemStack> iterator = event.getDrops().iterator(); iterator.hasNext(); ) { if(isUnshareable(iterator.next())) iterator.remove();; } } }