Fix item delete in own inventory
Dragging items across top and bottom inventories with own inventory open resulted in the overlapping content being deleted.
This commit is contained in:
		@@ -150,6 +150,20 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a raw slot number into a player inventory slot number.
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
 | 
			
		||||
     * player inventory slot number.
 | 
			
		||||
     *
 | 
			
		||||
     * @param view the open inventory view
 | 
			
		||||
     * @param rawSlot the raw slot in the view
 | 
			
		||||
     * @return the converted slot number
 | 
			
		||||
     */
 | 
			
		||||
    public int convertToPlayerSlot(InventoryView view, int rawSlot) {
 | 
			
		||||
        return this.accessor.getPlayerDataManager().convertToPlayerSlot(view, rawSlot);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean disableSaving() {
 | 
			
		||||
        return this.getConfig().getBoolean("settings.disable-saving", false);
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,18 @@ public interface IPlayerDataManager {
 | 
			
		||||
    @Nullable
 | 
			
		||||
    InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a raw slot number into a player inventory slot number.
 | 
			
		||||
     *
 | 
			
		||||
     * <p>Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
 | 
			
		||||
     * player inventory slot number.
 | 
			
		||||
     *
 | 
			
		||||
     * @param view the open inventory view
 | 
			
		||||
     * @param rawSlot the raw slot in the view
 | 
			
		||||
     * @return the converted slot number
 | 
			
		||||
     */
 | 
			
		||||
    int convertToPlayerSlot(InventoryView view, int rawSlot);
 | 
			
		||||
 | 
			
		||||
    void sendSystemMessage(@NotNull Player player, @NotNull String message);
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2021 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.internal;
 | 
			
		||||
 | 
			
		||||
import com.lishid.openinv.OpenInv;
 | 
			
		||||
import org.bukkit.entity.HumanEntity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.inventory.InventoryType;
 | 
			
		||||
import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.bukkit.inventory.InventoryView;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class OpenInventoryView extends InventoryView {
 | 
			
		||||
 | 
			
		||||
    private final Player player;
 | 
			
		||||
    private final ISpecialInventory inventory;
 | 
			
		||||
    private final String titleKey;
 | 
			
		||||
    private final String titleDefaultSuffix;
 | 
			
		||||
    private String title;
 | 
			
		||||
 | 
			
		||||
    public OpenInventoryView(Player player, ISpecialInventory inventory, String titleKey, String titleDefaultSuffix) {
 | 
			
		||||
        this.player = player;
 | 
			
		||||
        this.inventory = inventory;
 | 
			
		||||
        this.titleKey = titleKey;
 | 
			
		||||
        this.titleDefaultSuffix = titleDefaultSuffix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull Inventory getTopInventory() {
 | 
			
		||||
        return inventory.getBukkitInventory();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull Inventory getBottomInventory() {
 | 
			
		||||
        return getPlayer().getInventory();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull HumanEntity getPlayer() {
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull InventoryType getType() {
 | 
			
		||||
        return inventory.getBukkitInventory().getType();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public @NotNull String getTitle() {
 | 
			
		||||
        if (title == null) {
 | 
			
		||||
            HumanEntity owner = getPlayer();
 | 
			
		||||
 | 
			
		||||
            String localTitle = OpenInv.getPlugin(OpenInv.class)
 | 
			
		||||
                    .getLocalizedMessage(
 | 
			
		||||
                            owner,
 | 
			
		||||
                            titleKey,
 | 
			
		||||
                            "%player%",
 | 
			
		||||
                            owner.getName());
 | 
			
		||||
            if (localTitle != null) {
 | 
			
		||||
                title = localTitle;
 | 
			
		||||
            } else  {
 | 
			
		||||
                title = owner.getName() + titleDefaultSuffix;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -20,6 +20,9 @@ import com.lishid.openinv.OpenInv;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
 | 
			
		||||
import com.lishid.openinv.util.InventoryAccess;
 | 
			
		||||
import com.lishid.openinv.util.Permissions;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import org.bukkit.GameMode;
 | 
			
		||||
import org.bukkit.entity.HumanEntity;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
@@ -32,8 +35,10 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
 | 
			
		||||
import org.bukkit.event.inventory.InventoryDragEvent;
 | 
			
		||||
import org.bukkit.event.inventory.InventoryInteractEvent;
 | 
			
		||||
import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.bukkit.inventory.InventoryView;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Listener for inventory-related events to prevent modification of inventories where not allowed.
 | 
			
		||||
@@ -67,11 +72,6 @@ public class InventoryListener implements Listener {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Only specially handle actions in the player's own inventory.
 | 
			
		||||
        if (!event.getWhoClicked().equals(event.getView().getTopInventory().getHolder())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Safe cast - has to be a player to be the holder of a special player inventory.
 | 
			
		||||
        Player player = (Player) event.getWhoClicked();
 | 
			
		||||
 | 
			
		||||
@@ -102,14 +102,65 @@ public class InventoryListener implements Listener {
 | 
			
		||||
 | 
			
		||||
    @EventHandler(priority = EventPriority.LOWEST)
 | 
			
		||||
    public void onInventoryDrag(@NotNull final InventoryDragEvent event) {
 | 
			
		||||
        handleInventoryInteract(event);
 | 
			
		||||
        if (handleInventoryInteract(event)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        InventoryView view = event.getView();
 | 
			
		||||
        int topSize = view.getTopInventory().getSize();
 | 
			
		||||
 | 
			
		||||
        // Get bottom inventory active slots as player inventory slots.
 | 
			
		||||
        Set<Integer> slots = event.getRawSlots().stream()
 | 
			
		||||
                .filter(slot -> slot >= topSize)
 | 
			
		||||
                .map(slot -> plugin.convertToPlayerSlot(view, slot)).collect(Collectors.toSet());
 | 
			
		||||
 | 
			
		||||
        int overlapLosses = 0;
 | 
			
		||||
 | 
			
		||||
        // Count overlapping slots.
 | 
			
		||||
        for (Map.Entry<Integer, ItemStack> newItem : event.getNewItems().entrySet()) {
 | 
			
		||||
            int rawSlot = newItem.getKey();
 | 
			
		||||
 | 
			
		||||
            // Skip bottom inventory slots.
 | 
			
		||||
            if (rawSlot >= topSize) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int convertedSlot = plugin.convertToPlayerSlot(view, rawSlot);
 | 
			
		||||
 | 
			
		||||
            if (slots.contains(convertedSlot)) {
 | 
			
		||||
                overlapLosses += getCountDiff(view.getItem(rawSlot), newItem.getValue());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allow no overlap to proceed as usual.
 | 
			
		||||
        if (overlapLosses < 1) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ItemStack cursor = event.getCursor();
 | 
			
		||||
        if (cursor != null) {
 | 
			
		||||
            cursor.setAmount(cursor.getAmount() + overlapLosses);
 | 
			
		||||
        } else {
 | 
			
		||||
            cursor = event.getOldCursor().clone();
 | 
			
		||||
            cursor.setAmount(overlapLosses);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        event.setCursor(cursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private int getCountDiff(@Nullable ItemStack original, @NotNull ItemStack result) {
 | 
			
		||||
        if (original == null || original.getType() != result.getType()) {
 | 
			
		||||
            return result.getAmount();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result.getAmount() - original.getAmount();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle common InventoryInteractEvent functions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param event the InventoryInteractEvent
 | 
			
		||||
     * @return true unless the top inventory is an opened player inventory
 | 
			
		||||
     * @return true unless the top inventory is the holder's own inventory
 | 
			
		||||
     */
 | 
			
		||||
    private boolean handleInventoryInteract(@NotNull final InventoryInteractEvent event) {
 | 
			
		||||
        HumanEntity entity = event.getWhoClicked();
 | 
			
		||||
@@ -147,7 +198,8 @@ public class InventoryListener implements Listener {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
        // Only specially handle actions in the player's own inventory.
 | 
			
		||||
        return !event.getWhoClicked().equals(event.getView().getTopInventory().getHolder());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user