Search in sources :

Example 1 with GlowInventory

use of net.glowstone.inventory.GlowInventory in project Glowstone by GlowstoneMC.

the class WindowClickHandler method process.

private boolean process(GlowPlayer player, WindowClickMessage message) {
    int viewSlot = message.getSlot();
    InventoryView view = player.getOpenInventory();
    GlowInventory top = (GlowInventory) view.getTopInventory();
    GlowInventory bottom = (GlowInventory) view.getBottomInventory();
    ItemStack slotItem = InventoryUtil.itemOrEmpty(view.getItem(viewSlot));
    ItemStack cursor = player.getItemOnCursor();
    // check that the player has a correct view of the item
    if (!Objects.equals(message.getItem(), slotItem) && (message.getMode() == 0 || message.getMode() == 1)) {
        // in mode 3 (get) and 4 (drop), client does not send item in slot under cursor
        if (message.getMode() == 0 || !InventoryUtil.isEmpty(message.getItem())) {
            // recipe slot is not synced by design
            if (view.getTopInventory().getType() != InventoryType.CRAFTING || viewSlot >= view.getTopInventory().getSize() || ((GlowInventory) view.getTopInventory()).getSlot(viewSlot).getType() != SlotType.RESULT) {
                player.sendItemChange(viewSlot, slotItem);
                return false;
            }
        }
    }
    // determine inventory and slot clicked, used in some places
    // todo: attempt to allow for users to implement their own inventory?
    // CraftBukkit does not allow this but it may be worth the trouble for
    // the extensibility.
    GlowInventory inv;
    if (viewSlot < top.getSize()) {
        inv = top;
    } else {
        inv = bottom;
    }
    int invSlot = view.convertSlot(viewSlot);
    if (invSlot == -1 || viewSlot == -1) {
        return true;
    }
    SlotType slotType = inv.getSlotType(invSlot);
    // handle dragging
    if (message.getMode() == 5) {
        // 5 0 * start left drag
        // 5 1   add slot left drag
        // 5 2 * end left drag
        // 5 4 * start right drag
        // 5 5   add slot right drag
        // 5 6 * end right drag
        DragTracker drag = player.getInventory().getDragTracker();
        boolean right = message.getButton() >= 4;
        switch(message.getButton()) {
            // start left drag
            case 0:
            case // start right drag
            4:
                return drag.start(right);
            // add slot left
            case 1:
            case // add slot right
            5:
                return drag.addSlot(right, message.getSlot());
            // end left drag
            case 2:
            case // end right drag
            6:
                List<Integer> slots = drag.finish(right);
                if (slots == null || InventoryUtil.isEmpty(cursor)) {
                    return false;
                }
                ItemStack newCursor = cursor.clone();
                Map<Integer, ItemStack> newSlots = new HashMap<>();
                int perSlot = right ? 1 : cursor.getAmount() / slots.size();
                for (int dragSlot : slots) {
                    ItemStack oldItem = view.getItem(dragSlot);
                    if (InventoryUtil.isEmpty(oldItem) || cursor.isSimilar(oldItem)) {
                        Inventory dragInv = dragSlot < top.getSize() ? top : bottom;
                        int oldItemAmount = InventoryUtil.itemOrEmpty(oldItem).getAmount();
                        int transfer = Math.min(Math.min(perSlot, cursor.getAmount()), maxStack(dragInv, cursor.getType()) - oldItemAmount);
                        ItemStack newItem = combine(oldItem, cursor, transfer);
                        newSlots.put(dragSlot, newItem);
                        newCursor = amountOrEmpty(newCursor, newCursor.getAmount() - transfer);
                        if (InventoryUtil.isEmpty(newCursor)) {
                            break;
                        }
                    }
                }
                InventoryDragEvent event = new InventoryDragEvent(view, newCursor, cursor, right, newSlots);
                EventFactory.getInstance().callEvent(event);
                if (event.isCancelled()) {
                    return false;
                }
                for (Entry<Integer, ItemStack> entry : newSlots.entrySet()) {
                    view.setItem(entry.getKey(), entry.getValue());
                }
                player.setItemOnCursor(newCursor);
                return true;
            default:
                return false;
        }
    }
    // determine what action will be taken and fire event
    ClickType clickType = WindowClickLogic.getClickType(message.getMode(), message.getButton(), viewSlot);
    InventoryAction action = WindowClickLogic.getAction(clickType, slotType, cursor, slotItem);
    if (clickType == ClickType.UNKNOWN || action == InventoryAction.UNKNOWN) {
        // show a warning for unknown click type
        GlowServer.logger.warning(player.getName() + ": mystery window click " + clickType + "/" + action + ": " + message);
    }
    // deny CLONE_STACK for non-creative mode players
    if (action == InventoryAction.CLONE_STACK && player.getGameMode() != GameMode.CREATIVE) {
        action = InventoryAction.NOTHING;
    }
    // determine whether NO_AI, HOTBAR_MOVE_AND_READD or HOTBAR_SWAP should be executed
    if (clickType == ClickType.NUMBER_KEY) {
        ItemStack destItem = bottom.getItem(message.getButton());
        if (InventoryUtil.isEmpty(slotItem)) {
            if (InventoryUtil.isEmpty(destItem) || !inv.itemPlaceAllowed(invSlot, destItem)) {
                // both items are empty, do nothing
                // or, current item is empty and destItem cannot be moved into current slot
                action = InventoryAction.NOTHING;
            }
        } else if (inv != bottom || !inv.itemPlaceAllowed(invSlot, destItem)) {
            // target and source inventory are different or destItem cannot be placed in
            // current slot
            action = InventoryAction.HOTBAR_MOVE_AND_READD;
        }
    }
    if (WindowClickLogic.isPlaceAction(action)) {
        // check whether item can be dropped into the clicked slot
        if (!inv.itemPlaceAllowed(invSlot, cursor)) {
            // placement not allowed
            if (!InventoryUtil.isEmpty(slotItem) && slotItem.isSimilar(cursor)) {
                // item in slot is the same as item on cursor
                if (cursor.getAmount() + 1 == cursor.getMaxStackSize()) {
                    // There is still space under the cursor for one item
                    action = InventoryAction.PICKUP_ONE;
                } else if (cursor.getAmount() < cursor.getMaxStackSize()) {
                    // There is still some space under the cursor
                    action = InventoryAction.PICKUP_SOME;
                }
            } else {
                action = InventoryAction.NOTHING;
            }
        }
    }
    InventoryClickEvent event = null;
    if (top == inv && top instanceof GlowCraftingInventory && top.getSlotType(invSlot) == SlotType.RESULT) {
        // Clicked on output slot of crafting inventory
        if (InventoryUtil.isEmpty(slotItem)) {
            // No crafting recipe result, don't do anything
            action = InventoryAction.NOTHING;
        }
        int cursorAmount = InventoryUtil.itemOrEmpty(cursor).getAmount();
        if (message.getMode() == 0 && slotItem.isSimilar(cursor)) {
            if (!InventoryUtil.isEmpty(slotItem) && cursorAmount + slotItem.getAmount() <= slotItem.getMaxStackSize()) {
                // if the player can take the whole result
                if (WindowClickLogic.isPickupAction(action) || WindowClickLogic.isPlaceAction(action)) {
                    // always take the whole crafting result out of the crafting inventories
                    action = InventoryAction.PICKUP_ALL;
                } else if (action == InventoryAction.DROP_ONE_SLOT) {
                    // always drop the whole stack, not just single items
                    action = InventoryAction.DROP_ALL_SLOT;
                }
            } else {
                // if their cursor is full, do nothing
                action = InventoryAction.NOTHING;
            }
        }
        // this ignores whether the crafting process actually happens (full inventory, etc.)
        if (action != InventoryAction.NOTHING) {
            Recipe recipe = ((CraftingInventory) inv).getRecipe();
            if (clickType == ClickType.NUMBER_KEY) {
                event = new CraftItemEvent(recipe, view, slotType, viewSlot, clickType, action, message.getButton());
            } else {
                event = new CraftItemEvent(recipe, view, slotType, viewSlot, clickType, action);
            }
        }
    }
    if (event == null) {
        if (clickType == ClickType.NUMBER_KEY) {
            event = new InventoryClickEvent(view, slotType, viewSlot, clickType, action, message.getButton());
        } else {
            event = new InventoryClickEvent(view, slotType, viewSlot, clickType, action);
        }
    }
    EventFactory.getInstance().callEvent(event);
    if (event.isCancelled()) {
        int slot = event.getSlot();
        player.getSession().send(new SetWindowSlotMessage(player.getOpenWindowId(), slot, event.getInventory().getItem(slot)));
        player.getSession().send(new SetWindowSlotMessage(-1, -1, player.getItemOnCursor()));
        return true;
    }
    boolean handled = true;
    switch(action) {
        case NOTHING:
            break;
        case UNKNOWN:
            // any action the client tried to take should be denied
            return false;
        // PICKUP_*
        case PICKUP_ALL:
            view.setItem(viewSlot, InventoryUtil.createEmptyStack());
            int cursorAmount = InventoryUtil.itemOrEmpty(cursor).getAmount();
            player.setItemOnCursor(amountOrEmpty(slotItem, cursorAmount + slotItem.getAmount()));
            break;
        case PICKUP_HALF:
            // pick up half (favor picking up)
            int keepAmount = slotItem.getAmount() / 2;
            ItemStack newCursor = slotItem.clone();
            newCursor.setAmount(slotItem.getAmount() - keepAmount);
            inv.setItem(invSlot, amountOrEmpty(slotItem, keepAmount));
            player.setItemOnCursor(newCursor);
            break;
        case PICKUP_SOME:
            // pick up as many items as possible
            int pickUp = Math.min(cursor.getMaxStackSize() - cursor.getAmount(), slotItem.getAmount());
            view.setItem(viewSlot, amountOrEmpty(slotItem, slotItem.getAmount() - pickUp));
            player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() + pickUp));
            break;
        case PICKUP_ONE:
            view.setItem(invSlot, amountOrEmpty(slotItem, slotItem.getAmount() - 1));
            player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() + 1));
            break;
        // PLACE_*
        case PLACE_ALL:
            view.setItem(viewSlot, combine(slotItem, cursor, cursor.getAmount()));
            player.setItemOnCursor(InventoryUtil.createEmptyStack());
            break;
        case PLACE_SOME:
            {
                // slotItem *should* never be empty in this situation?
                int transfer = Math.min(cursor.getAmount(), maxStack(inv, slotItem.getType()) - slotItem.getAmount());
                view.setItem(viewSlot, combine(slotItem, cursor, transfer));
                player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() - transfer));
                break;
            }
        case PLACE_ONE:
            view.setItem(viewSlot, combine(slotItem, cursor, 1));
            player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() - 1));
            break;
        case SWAP_WITH_CURSOR:
            view.setItem(viewSlot, cursor);
            player.setItemOnCursor(slotItem);
            break;
        // DROP_*
        case DROP_ALL_CURSOR:
            if (!InventoryUtil.isEmpty(cursor)) {
                drop(player, cursor);
                player.setItemOnCursor(InventoryUtil.createEmptyStack());
            }
            break;
        case DROP_ONE_CURSOR:
            if (!InventoryUtil.isEmpty(cursor)) {
                drop(player, amountOrEmpty(cursor.clone(), 1));
                player.setItemOnCursor(amountOrEmpty(cursor, cursor.getAmount() - 1));
            }
            break;
        case DROP_ALL_SLOT:
            if (!InventoryUtil.isEmpty(slotItem)) {
                drop(player, slotItem);
                view.setItem(viewSlot, InventoryUtil.createEmptyStack());
            }
            break;
        case DROP_ONE_SLOT:
            if (InventoryUtil.isEmpty(slotItem)) {
                drop(player, amountOrEmpty(slotItem.clone(), 1));
                view.setItem(viewSlot, amountOrEmpty(slotItem, slotItem.getAmount() - 1));
            }
            break;
        // shift-click
        case MOVE_TO_OTHER_INVENTORY:
            if (!InventoryUtil.isEmpty(slotItem)) {
                inv.handleShiftClick(player, view, viewSlot, slotItem);
            }
            break;
        case HOTBAR_MOVE_AND_READD:
        case HOTBAR_SWAP:
            GlowPlayerInventory playerInv = player.getInventory();
            int hotbarSlot = message.getButton();
            ItemStack destItem = playerInv.getItem(hotbarSlot);
            if (InventoryUtil.isEmpty(slotItem)) {
                // nothing in current slot
                if (InventoryUtil.isEmpty(destItem)) {
                    // no action
                    return false;
                } else {
                    // do nothing if current slots does not accept the item
                    if (action == InventoryAction.HOTBAR_SWAP) {
                        inv.setItem(invSlot, destItem);
                        playerInv.setItem(hotbarSlot, InventoryUtil.createEmptyStack());
                    }
                    return true;
                }
            } else {
                if (InventoryUtil.isEmpty(destItem)) {
                    // move from current slot to hotbar
                    playerInv.setItem(hotbarSlot, slotItem);
                    inv.setItem(invSlot, InventoryUtil.createEmptyStack());
                    return true;
                } else {
                    // both are non-empty, swap them
                    playerInv.setItem(hotbarSlot, slotItem);
                    if (action == InventoryAction.HOTBAR_SWAP) {
                        inv.setItem(invSlot, destItem);
                    } else {
                        inv.setItem(invSlot, InventoryUtil.createEmptyStack());
                        playerInv.addItem(destItem);
                    }
                    return true;
                }
            }
        case CLONE_STACK:
            // only in creative and with no item on cursor handled earlier
            // copy and maximize item
            ItemStack stack = slotItem.clone();
            stack.setAmount(stack.getType().getMaxStackSize());
            player.setItemOnCursor(stack);
            break;
        case COLLECT_TO_CURSOR:
            if (InventoryUtil.isEmpty(cursor)) {
                return false;
            }
            int slotCount = view.countSlots();
            for (int i = 0; i < slotCount && cursor.getAmount() < maxStack(inv, cursor.getType()); ++i) {
                ItemStack item = view.getItem(i);
                SlotType type = (i < top.getSize() ? top : bottom).getSlotType(view.convertSlot(i));
                if (InventoryUtil.isEmpty(item) || !cursor.isSimilar(item) || type == SlotType.RESULT) {
                    continue;
                }
                int transfer = Math.min(item.getAmount(), maxStack(inv, cursor.getType()) - cursor.getAmount());
                cursor.setAmount(cursor.getAmount() + transfer);
                view.setItem(i, amountOrEmpty(item, item.getAmount() - transfer));
            }
            break;
        default:
            handled = false;
    }
    if (handled && top == inv && top instanceof GlowCraftingInventory && top.getSlotType(invSlot) == SlotType.RESULT && action != MOVE_TO_OTHER_INVENTORY && action != NOTHING) {
        // If we are crafting (but not using shift click because no more items can be crafted
        // for the given pattern. If a new item can be crafted with another pattern, a new
        // click is required).
        final GlowCraftingInventory glowCraftingInventory = (GlowCraftingInventory) top;
        glowCraftingInventory.craft();
        // Notify the player the result slot changed
        player.sendItemChange(viewSlot, glowCraftingInventory.getResult());
    }
    if (!handled) {
        GlowServer.logger.warning(player.getName() + ": unhandled click action " + action + " for " + message);
    }
    return handled;
}
Also used : CraftingInventory(org.bukkit.inventory.CraftingInventory) GlowCraftingInventory(net.glowstone.inventory.GlowCraftingInventory) HashMap(java.util.HashMap) Recipe(org.bukkit.inventory.Recipe) SlotType(org.bukkit.event.inventory.InventoryType.SlotType) InventoryAction(org.bukkit.event.inventory.InventoryAction) DragTracker(net.glowstone.inventory.DragTracker) InventoryDragEvent(org.bukkit.event.inventory.InventoryDragEvent) InventoryClickEvent(org.bukkit.event.inventory.InventoryClickEvent) GlowCraftingInventory(net.glowstone.inventory.GlowCraftingInventory) InventoryView(org.bukkit.inventory.InventoryView) ClickType(org.bukkit.event.inventory.ClickType) SetWindowSlotMessage(net.glowstone.net.message.play.inv.SetWindowSlotMessage) GlowInventory(net.glowstone.inventory.GlowInventory) CraftItemEvent(org.bukkit.event.inventory.CraftItemEvent) ItemStack(org.bukkit.inventory.ItemStack) CraftingInventory(org.bukkit.inventory.CraftingInventory) Inventory(org.bukkit.inventory.Inventory) GlowInventory(net.glowstone.inventory.GlowInventory) GlowPlayerInventory(net.glowstone.inventory.GlowPlayerInventory) GlowCraftingInventory(net.glowstone.inventory.GlowCraftingInventory) GlowPlayerInventory(net.glowstone.inventory.GlowPlayerInventory)

Example 2 with GlowInventory

use of net.glowstone.inventory.GlowInventory in project Glowstone by GlowstoneMC.

the class InventoryUtilTest method testRandomItem.

@Test
public void testRandomItem() {
    Random random = new Random();
    Inventory inventory = new GlowInventory(null, InventoryType.CHEST);
    assertThat(-1, is(InventoryUtil.getRandomSlot(random, inventory, true)));
    assertThat(InventoryUtil.getRandomSlot(random, inventory, false), OrderingComparison.greaterThanOrEqualTo(0));
    inventory.setItem(0, new ItemStack(Material.APPLE));
    assertThat(0, is(InventoryUtil.getRandomSlot(random, inventory, true)));
    inventory.setItem(1, new ItemStack(Material.CARROT));
    assertThat(InventoryUtil.getRandomSlot(random, inventory, true), OrderingComparison.greaterThanOrEqualTo(0));
}
Also used : Random(java.util.Random) GlowInventory(net.glowstone.inventory.GlowInventory) ItemStack(org.bukkit.inventory.ItemStack) GlowInventory(net.glowstone.inventory.GlowInventory) Inventory(org.bukkit.inventory.Inventory) Test(org.junit.jupiter.api.Test)

Example 3 with GlowInventory

use of net.glowstone.inventory.GlowInventory in project Glowstone by GlowstoneMC.

the class ArmorDispenseBehavior method dispenseStack.

@Override
protected ItemStack dispenseStack(GlowBlock block, ItemStack stack) {
    BlockFace facing = BlockDispenser.getFacing(block);
    Location targetLocation = block.getLocation().clone().add(facing.getModX(), facing.getModY(), facing.getModZ());
    // Find all nearby entities and see if they are players or armor stands
    List<LivingEntity> entities = new ArrayList<>();
    for (Entity entity : targetLocation.getWorld().getNearbyEntities(targetLocation, 3, 3, 3)) {
        switch(entity.getType()) {
            case PLAYER:
            case ARMOR_STAND:
                entities.add((LivingEntity) entity);
                break;
            default:
        }
    }
    boolean targetLocationTest1;
    boolean targetLocationTest2;
    // Loop through entities to see if any are in the location where armor would be dispensed
    for (LivingEntity player : entities) {
        targetLocationTest1 = (player.getLocation().getBlockX() == targetLocation.getX() && player.getLocation().getBlockY() == targetLocation.getY() && player.getLocation().getBlockZ() == targetLocation.getZ());
        targetLocationTest2 = (player.getEyeLocation().getBlockX() == targetLocation.getX() && player.getEyeLocation().getBlockY() == targetLocation.getY() && player.getEyeLocation().getBlockZ() == targetLocation.getZ());
        if ((targetLocationTest1 || targetLocationTest2)) {
            return ((GlowInventory) ((Player) player).getInventory()).tryToFillSlots(stack, 36, 40);
        }
    }
    // Fallback
    return INSTANCE.dispense(block, stack);
}
Also used : LivingEntity(org.bukkit.entity.LivingEntity) Entity(org.bukkit.entity.Entity) LivingEntity(org.bukkit.entity.LivingEntity) BlockFace(org.bukkit.block.BlockFace) ArrayList(java.util.ArrayList) GlowInventory(net.glowstone.inventory.GlowInventory) Location(org.bukkit.Location)

Example 4 with GlowInventory

use of net.glowstone.inventory.GlowInventory in project Glowstone by GlowstoneMC.

the class CreativeItemHandler method handle.

@Override
public void handle(GlowSession session, CreativeItemMessage message) {
    GlowPlayer player = session.getPlayer();
    // CraftBukkit does use a inventory view with both inventories set to the player's inventory
    // for the creative inventory as there is no second inventory (no crafting) visible for the
    // client
    InventoryView view = player.getOpenInventory();
    // only if creative mode; only if default (player) inventory
    if (player.getGameMode() != GameMode.CREATIVE || !GlowInventoryView.isDefault(player.getOpenInventory())) {
        player.kickPlayer(GlowstoneMessages.Kick.CREATIVE_ITEM.get());
        return;
    }
    ItemStack stack = ItemIds.sanitize(message.getItem());
    // clicking outside drops the item
    EventFactory eventFactory = EventFactory.getInstance();
    if (message.getSlot() < 0) {
        InventoryCreativeEvent event = eventFactory.callEvent(new InventoryCreativeEvent(view, SlotType.OUTSIDE, -999, stack));
        if (event.isCancelled()) {
            session.send(new SetWindowSlotMessage(-1, -1, stack));
        } else {
            player.drop(event.getCursor());
        }
        return;
    }
    int viewSlot = message.getSlot();
    // this happens quiet often as the client tends to update the whole inventory at once
    if (Objects.equals(stack, view.getItem(viewSlot))) {
        return;
    }
    GlowInventory inv = player.getInventory();
    int slot = view.convertSlot(viewSlot);
    SlotType type = inv.getSlotType(slot);
    InventoryCreativeEvent event = eventFactory.callEvent(new InventoryCreativeEvent(view, type, viewSlot, stack));
    if (event.isCancelled()) {
        // send original slot to player to prevent async inventories
        player.sendItemChange(viewSlot, view.getItem(viewSlot));
        // don't keep track of player's current item, just give them back what they tried to
        // place
        session.send(new SetWindowSlotMessage(-1, -1, stack));
        return;
    }
    view.setItem(viewSlot, stack);
}
Also used : GlowInventoryView(net.glowstone.inventory.GlowInventoryView) InventoryView(org.bukkit.inventory.InventoryView) InventoryCreativeEvent(org.bukkit.event.inventory.InventoryCreativeEvent) GlowPlayer(net.glowstone.entity.GlowPlayer) SetWindowSlotMessage(net.glowstone.net.message.play.inv.SetWindowSlotMessage) GlowInventory(net.glowstone.inventory.GlowInventory) EventFactory(net.glowstone.EventFactory) ItemStack(org.bukkit.inventory.ItemStack) SlotType(org.bukkit.event.inventory.InventoryType.SlotType)

Aggregations

GlowInventory (net.glowstone.inventory.GlowInventory)4 ItemStack (org.bukkit.inventory.ItemStack)3 SetWindowSlotMessage (net.glowstone.net.message.play.inv.SetWindowSlotMessage)2 SlotType (org.bukkit.event.inventory.InventoryType.SlotType)2 Inventory (org.bukkit.inventory.Inventory)2 InventoryView (org.bukkit.inventory.InventoryView)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Random (java.util.Random)1 EventFactory (net.glowstone.EventFactory)1 GlowPlayer (net.glowstone.entity.GlowPlayer)1 DragTracker (net.glowstone.inventory.DragTracker)1 GlowCraftingInventory (net.glowstone.inventory.GlowCraftingInventory)1 GlowInventoryView (net.glowstone.inventory.GlowInventoryView)1 GlowPlayerInventory (net.glowstone.inventory.GlowPlayerInventory)1 Location (org.bukkit.Location)1 BlockFace (org.bukkit.block.BlockFace)1 Entity (org.bukkit.entity.Entity)1 LivingEntity (org.bukkit.entity.LivingEntity)1 ClickType (org.bukkit.event.inventory.ClickType)1