mirror of
https://github.com/TotalFreedomMC/OpenInv.git
synced 2024-12-23 00:15:08 +00:00
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:
parent
dad1e16c18
commit
1c9d133ed1
5 changed files with 233 additions and 68 deletions
|
@ -16,9 +16,9 @@
|
||||||
|
|
||||||
package com.lishid.openinv.internal.v1_16_R3;
|
package com.lishid.openinv.internal.v1_16_R3;
|
||||||
|
|
||||||
import com.lishid.openinv.OpenInv;
|
|
||||||
import com.lishid.openinv.internal.IPlayerDataManager;
|
import com.lishid.openinv.internal.IPlayerDataManager;
|
||||||
import com.lishid.openinv.internal.ISpecialInventory;
|
import com.lishid.openinv.internal.ISpecialInventory;
|
||||||
|
import com.lishid.openinv.internal.OpenInventoryView;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -28,7 +28,6 @@ import net.minecraft.server.v1_16_R3.ChatMessageType;
|
||||||
import net.minecraft.server.v1_16_R3.Container;
|
import net.minecraft.server.v1_16_R3.Container;
|
||||||
import net.minecraft.server.v1_16_R3.Containers;
|
import net.minecraft.server.v1_16_R3.Containers;
|
||||||
import net.minecraft.server.v1_16_R3.Entity;
|
import net.minecraft.server.v1_16_R3.Entity;
|
||||||
import net.minecraft.server.v1_16_R3.EntityHuman;
|
|
||||||
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||||
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
|
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
|
||||||
|
@ -36,7 +35,6 @@ import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||||
import net.minecraft.server.v1_16_R3.PacketPlayOutChat;
|
import net.minecraft.server.v1_16_R3.PacketPlayOutChat;
|
||||||
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
|
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
|
||||||
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
|
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
|
||||||
import net.minecraft.server.v1_16_R3.PlayerInventory;
|
|
||||||
import net.minecraft.server.v1_16_R3.SystemUtils;
|
import net.minecraft.server.v1_16_R3.SystemUtils;
|
||||||
import net.minecraft.server.v1_16_R3.World;
|
import net.minecraft.server.v1_16_R3.World;
|
||||||
import net.minecraft.server.v1_16_R3.WorldNBTStorage;
|
import net.minecraft.server.v1_16_R3.WorldNBTStorage;
|
||||||
|
@ -49,10 +47,7 @@ import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
|
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
|
||||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
|
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
|
||||||
import org.bukkit.entity.HumanEntity;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
import org.bukkit.inventory.InventoryView;
|
import org.bukkit.inventory.InventoryView;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
@ -195,68 +190,20 @@ public class PlayerDataManager implements IPlayerDataManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String title;
|
InventoryView view = getView(player, inventory);
|
||||||
if (inventory instanceof SpecialEnderChest) {
|
|
||||||
HumanEntity owner = (HumanEntity) ((SpecialEnderChest) inventory).getBukkitOwner();
|
if (view == null) {
|
||||||
title = OpenInv.getPlugin(OpenInv.class).getLocalizedMessage(player, "container.enderchest", "%player%", owner.getName());
|
|
||||||
if (title == null) {
|
|
||||||
title = owner.getName() + "'s Ender Chest";
|
|
||||||
}
|
|
||||||
} else if (inventory instanceof SpecialPlayerInventory) {
|
|
||||||
EntityHuman owner = ((PlayerInventory) inventory).player;
|
|
||||||
title = OpenInv.getPlugin(OpenInv.class).getLocalizedMessage(player, "container.player", "%player%", owner.getName());
|
|
||||||
if (title == null) {
|
|
||||||
title = owner.getName() + "'s Inventory";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return player.openInventory(inventory.getBukkitInventory());
|
return player.openInventory(inventory.getBukkitInventory());
|
||||||
}
|
}
|
||||||
|
|
||||||
String finalTitle = title;
|
Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
|
||||||
Container container = new CraftContainer(new InventoryView() {
|
|
||||||
@Override
|
|
||||||
public @NotNull Inventory getTopInventory() {
|
|
||||||
return inventory.getBukkitInventory();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public @NotNull Inventory getBottomInventory() {
|
|
||||||
return player.getInventory();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public @NotNull HumanEntity getPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public @NotNull InventoryType getType() {
|
|
||||||
return inventory.getBukkitInventory().getType();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public @NotNull String getTitle() {
|
|
||||||
return finalTitle;
|
|
||||||
}
|
|
||||||
}, nmsPlayer, nmsPlayer.nextContainerCounter()) {
|
|
||||||
@Override
|
@Override
|
||||||
public Containers<?> getType() {
|
public Containers<?> getType() {
|
||||||
switch (inventory.getBukkitInventory().getSize()) {
|
return getContainers(inventory.getBukkitInventory().getSize());
|
||||||
case 9:
|
|
||||||
return Containers.GENERIC_9X1;
|
|
||||||
case 18:
|
|
||||||
return Containers.GENERIC_9X2;
|
|
||||||
case 27:
|
|
||||||
default:
|
|
||||||
return Containers.GENERIC_9X3;
|
|
||||||
case 36:
|
|
||||||
return Containers.GENERIC_9X4;
|
|
||||||
case 41: // PLAYER
|
|
||||||
case 45:
|
|
||||||
return Containers.GENERIC_9X5;
|
|
||||||
case 54:
|
|
||||||
return Containers.GENERIC_9X6;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
container.setTitle(new ChatComponentText(title));
|
container.setTitle(new ChatComponentText(view.getTitle()));
|
||||||
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
|
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
|
||||||
|
|
||||||
if (container == null) {
|
if (container == null) {
|
||||||
|
@ -272,6 +219,63 @@ public class PlayerDataManager implements IPlayerDataManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) {
|
||||||
|
if (inventory instanceof SpecialEnderChest) {
|
||||||
|
return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest");
|
||||||
|
} else if (inventory instanceof SpecialPlayerInventory) {
|
||||||
|
return new OpenInventoryView(player, inventory, "container.player", "'s Inventory");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull Containers<?> getContainers(int inventorySize) {
|
||||||
|
switch (inventorySize) {
|
||||||
|
case 9:
|
||||||
|
return Containers.GENERIC_9X1;
|
||||||
|
case 18:
|
||||||
|
return Containers.GENERIC_9X2;
|
||||||
|
case 36:
|
||||||
|
return Containers.GENERIC_9X4;
|
||||||
|
case 41: // PLAYER
|
||||||
|
case 45:
|
||||||
|
return Containers.GENERIC_9X5;
|
||||||
|
case 54:
|
||||||
|
return Containers.GENERIC_9X6;
|
||||||
|
case 27:
|
||||||
|
default:
|
||||||
|
return Containers.GENERIC_9X3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int convertToPlayerSlot(InventoryView view, int rawSlot) {
|
||||||
|
int topSize = view.getTopInventory().getSize();
|
||||||
|
if (topSize <= rawSlot) {
|
||||||
|
// Slot is not inside special inventory, use Bukkit logic.
|
||||||
|
return view.convertSlot(rawSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main inventory, slots 0-26 -> 9-35
|
||||||
|
if (rawSlot < 27) {
|
||||||
|
return rawSlot + 9;
|
||||||
|
}
|
||||||
|
// Hotbar, slots 27-35 -> 0-8
|
||||||
|
if (rawSlot < 36) {
|
||||||
|
return rawSlot - 27;
|
||||||
|
}
|
||||||
|
// Armor, slots 36-39 -> 39-36
|
||||||
|
if (rawSlot < 40) {
|
||||||
|
return 36 + (39 - rawSlot);
|
||||||
|
}
|
||||||
|
// Off hand
|
||||||
|
if (rawSlot == 40) {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
// Drop slots, "out of inventory"
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendSystemMessage(@NotNull Player player, @NotNull String message) {
|
public void sendSystemMessage(@NotNull Player player, @NotNull String message) {
|
||||||
int newline = message.indexOf('\n');
|
int newline = message.indexOf('\n');
|
||||||
|
|
|
@ -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
|
@Override
|
||||||
public boolean disableSaving() {
|
public boolean disableSaving() {
|
||||||
return this.getConfig().getBoolean("settings.disable-saving", false);
|
return this.getConfig().getBoolean("settings.disable-saving", false);
|
||||||
|
|
|
@ -54,6 +54,18 @@ public interface IPlayerDataManager {
|
||||||
@Nullable
|
@Nullable
|
||||||
InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
|
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);
|
void sendSystemMessage(@NotNull Player player, @NotNull String message);
|
||||||
|
|
||||||
@NotNull
|
@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.internal.ISpecialPlayerInventory;
|
||||||
import com.lishid.openinv.util.InventoryAccess;
|
import com.lishid.openinv.util.InventoryAccess;
|
||||||
import com.lishid.openinv.util.Permissions;
|
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.GameMode;
|
||||||
import org.bukkit.entity.HumanEntity;
|
import org.bukkit.entity.HumanEntity;
|
||||||
import org.bukkit.entity.Player;
|
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.InventoryDragEvent;
|
||||||
import org.bukkit.event.inventory.InventoryInteractEvent;
|
import org.bukkit.event.inventory.InventoryInteractEvent;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryView;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for inventory-related events to prevent modification of inventories where not allowed.
|
* Listener for inventory-related events to prevent modification of inventories where not allowed.
|
||||||
|
@ -67,11 +72,6 @@ public class InventoryListener implements Listener {
|
||||||
return;
|
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.
|
// Safe cast - has to be a player to be the holder of a special player inventory.
|
||||||
Player player = (Player) event.getWhoClicked();
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
|
||||||
|
@ -102,14 +102,65 @@ public class InventoryListener implements Listener {
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onInventoryDrag(@NotNull final InventoryDragEvent event) {
|
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.
|
* Handle common InventoryInteractEvent functions.
|
||||||
*
|
*
|
||||||
* @param event the InventoryInteractEvent
|
* @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) {
|
private boolean handleInventoryInteract(@NotNull final InventoryInteractEvent event) {
|
||||||
HumanEntity entity = event.getWhoClicked();
|
HumanEntity entity = event.getWhoClicked();
|
||||||
|
@ -147,7 +198,8 @@ public class InventoryListener implements Listener {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// Only specially handle actions in the player's own inventory.
|
||||||
|
return !event.getWhoClicked().equals(event.getView().getTopInventory().getHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue