Fix item dupe in own inventory

Reduce desync for other actions in own inventory

Closes #182
This commit is contained in:
Jikoo 2021-03-16 11:59:07 -04:00
parent 519dd7da33
commit dad1e16c18
No known key found for this signature in database
GPG key ID: 37FF68B07F639098

View file

@ -16,7 +16,8 @@
package com.lishid.openinv.listeners;
import com.lishid.openinv.IOpenInv;
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.util.InventoryAccess;
import com.lishid.openinv.util.Permissions;
import org.bukkit.GameMode;
@ -25,11 +26,14 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
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.ItemStack;
import org.jetbrains.annotations.NotNull;
/**
* Listener for inventory-related events to prevent modification of inventories where not allowed.
@ -38,14 +42,14 @@ import org.bukkit.inventory.Inventory;
*/
public class InventoryListener implements Listener {
private final IOpenInv plugin;
private final OpenInv plugin;
public InventoryListener(final IOpenInv plugin) {
public InventoryListener(final OpenInv plugin) {
this.plugin = plugin;
}
@EventHandler
public void onInventoryClose(final InventoryCloseEvent event) {
public void onInventoryClose(@NotNull final InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player)) {
return;
}
@ -58,37 +62,92 @@ public class InventoryListener implements Listener {
}
@EventHandler(priority = EventPriority.LOWEST)
public void onInventoryClick(InventoryClickEvent event) {
onInventoryInteract(event);
public void onInventoryClick(@NotNull final InventoryClickEvent event) {
if (handleInventoryInteract(event)) {
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();
if (event.getAction() != InventoryAction.MOVE_TO_OTHER_INVENTORY) {
// All own-inventory interactions require updates to display properly.
// Update in same tick after event completion.
this.plugin.getServer().getScheduler().runTask(this.plugin, player::updateInventory);
return;
}
// Extra handling for MOVE_TO_OTHER_INVENTORY - apparently Mojang no longer removes the item from the target
// inventory prior to adding it to existing stacks.
ItemStack currentItem = event.getCurrentItem();
if (currentItem == null) {
// Other plugin doing some sort of handling (would be NOTHING for null item otherwise), ignore.
return;
}
ItemStack clone = currentItem.clone();
event.setCurrentItem(null);
// Complete add action in same tick after event completion.
this.plugin.getServer().getScheduler().runTask(this.plugin, () -> {
player.getInventory().addItem(clone);
player.updateInventory();
});
}
@EventHandler(priority = EventPriority.LOWEST)
public void onInventoryDrag(InventoryDragEvent event) {
onInventoryInteract(event);
public void onInventoryDrag(@NotNull final InventoryDragEvent event) {
handleInventoryInteract(event);
}
private void onInventoryInteract(InventoryInteractEvent event) {
/**
* Handle common InventoryInteractEvent functions.
*
* @param event the InventoryInteractEvent
* @return true unless the top inventory is an opened player inventory
*/
private boolean handleInventoryInteract(@NotNull final InventoryInteractEvent event) {
HumanEntity entity = event.getWhoClicked();
// Un-cancel spectator interactions.
if (Permissions.SPECTATE.hasPermission(entity) && entity.getGameMode() == GameMode.SPECTATOR) {
event.setCancelled(false);
}
if (event.isCancelled()) {
return;
return true;
}
Inventory inventory = event.getInventory();
Inventory inventory = event.getView().getTopInventory();
if (InventoryAccess.isPlayerInventory(inventory)) {
if (!Permissions.EDITINV.hasPermission(entity)) {
event.setCancelled(true);
}
} else if (InventoryAccess.isEnderChest(inventory)) {
// Is the inventory a special ender chest?
if (InventoryAccess.isEnderChest(inventory)) {
// Disallow ender chest interaction for users without edit permission.
if (!Permissions.EDITENDER.hasPermission(entity)) {
event.setCancelled(true);
}
return true;
}
ISpecialPlayerInventory playerInventory = InventoryAccess.getPlayerInventory(inventory);
// Ignore inventories other than special player inventories.
if (playerInventory == null) {
return true;
}
// Disallow player inventory interaction for users without edit permission.
if (!Permissions.EDITINV.hasPermission(entity)) {
event.setCancelled(true);
return true;
}
return false;
}
}