Added logging for dropping items into a hopper

This commit is contained in:
Intelli committed 2026-04-24 09:50:00 -06:00
1 parent 829bcc530d
commit cdc8082c3e
3 files changed
+171 -5

No files matched your search

@@ -53,6 +53,9 @@ public class ContainerLogger extends Queue {
else if (type == Material.JUKEBOX || type == Material.ARMOR_STAND) {
contents = (ItemStack[]) ((Object[]) container)[1];
}
else if (container instanceof ItemStack[]) {
contents = (ItemStack[]) container;
}
else {
Inventory inventory = (Inventory) container;
if (inventory != null) {
@@ -13,6 +13,8 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.Hopper;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -22,6 +24,7 @@ import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.BlockInventoryHolder;
import org.bukkit.inventory.Inventory;
@@ -139,6 +142,15 @@ public final class InventoryChangeListener extends Queue implements Listener {
inventoryData = inventory.getContents();
}
return queueContainerTransaction(user, playerLocation, type, inventory, inventoryData, null);
}
}
}
return false;
}
private static boolean queueContainerTransaction(String user, Location playerLocation, Material type, Object inventory, ItemStack[] inventoryData, ItemStack[] forceInventoryData) {
int x = playerLocation.getBlockX();
int y = playerLocation.getBlockY();
int z = playerLocation.getBlockZ();
@@ -226,15 +238,14 @@ public final class InventoryChangeListener extends Queue implements Listener {
ConfigHandler.oldContainer.put(loggingChestId, list);
}
if (forceInventoryData != null) {
ConfigHandler.forceContainer.computeIfAbsent(loggingChestId, k -> new ArrayList<>()).add(ItemUtils.getContainerState(forceInventoryData));
}
ConfigHandler.transactingChest.computeIfAbsent(transactingChestId, k -> Collections.synchronizedList(new ArrayList<>()));
Queue.queueContainerTransaction(user, playerLocation, type, inventory, chestId);
return true;
}
}
}
return false;
}
static void onInventoryInteractAsync(Player player, Inventory inventory, boolean enderChest) {
if (inventory == null) {
@@ -542,6 +553,105 @@ public final class InventoryChangeListener extends Queue implements Listener {
HopperPullListener.processHopperPull(location, "#hopper", sourceHolder, destinationHolder, event.getItem());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
protected void onInventoryPickupItem(InventoryPickupItemEvent event) {
Inventory inventory = event.getInventory();
if (inventory == null) {
return;
}
InventoryHolder holder = PaperAdapter.ADAPTER.getHolder(inventory, false);
if (!(holder instanceof Hopper)) {
return;
}
Location location = inventory.getLocation();
if (location == null) {
location = ((Hopper) holder).getLocation();
}
if (location == null || !Config.getConfig(location.getWorld()).ITEM_TRANSACTIONS) {
return;
}
Item item = event.getItem();
if (item == null) {
return;
}
ItemStack[] oldContents = ItemUtils.getContainerState(inventory.getContents());
ItemStack[] newContents = addPickedItem(oldContents, item.getItemStack(), inventory.getMaxStackSize());
if (newContents == null) {
return;
}
String user = PlayerDropItemListener.getDroppedItemUser(item.getUniqueId());
if (user == null) {
user = "#hopper";
}
queueContainerTransaction(user, location, Material.HOPPER, newContents, oldContents, newContents);
}
private static ItemStack[] addPickedItem(ItemStack[] contents, ItemStack itemStack, int inventoryMaxStackSize) {
if (contents == null || itemStack == null || itemStack.getAmount() <= 0 || itemStack.getType() == Material.AIR) {
return null;
}
ItemStack[] result = ItemUtils.getContainerState(contents);
ItemStack pickedItem = itemStack.clone();
int remaining = pickedItem.getAmount();
for (ItemStack item : result) {
if (remaining <= 0) {
break;
}
if (item == null || item.getType() == Material.AIR || !item.isSimilar(pickedItem)) {
continue;
}
int maxStackSize = getMaxStackSize(item, inventoryMaxStackSize);
int accepted = Math.min(remaining, maxStackSize - item.getAmount());
if (accepted > 0) {
item.setAmount(item.getAmount() + accepted);
remaining -= accepted;
}
}
for (int i = 0; i < result.length && remaining > 0; i++) {
ItemStack item = result[i];
if (item != null && item.getType() != Material.AIR) {
continue;
}
int accepted = Math.min(remaining, getMaxStackSize(pickedItem, inventoryMaxStackSize));
ItemStack addedItem = pickedItem.clone();
addedItem.setAmount(accepted);
result[i] = addedItem;
remaining -= accepted;
}
if (remaining == pickedItem.getAmount()) {
return null;
}
return result;
}
private static int getMaxStackSize(ItemStack itemStack, int inventoryMaxStackSize) {
int maxStackSize = itemStack.getMaxStackSize();
if (inventoryMaxStackSize > 0 && (inventoryMaxStackSize < maxStackSize || maxStackSize == -1)) {
maxStackSize = inventoryMaxStackSize;
}
if (maxStackSize == -1) {
return 1;
}
return maxStackSize;
}
private boolean isAdvancedChest(Inventory inventory) {
return CoreProtect.getInstance().isAdvancedChestsEnabled() && AdvancedChestsAPI.getInventoryManager().getAdvancedChest(inventory) != null;
}
@@ -3,6 +3,10 @@ package net.coreprotect.listener.player;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.bukkit.Location;
import org.bukkit.entity.Item;
@@ -18,6 +22,19 @@ import net.coreprotect.consumer.Queue;
public final class PlayerDropItemListener extends Queue implements Listener {
private static final long ITEM_DROP_ATTRIBUTION_MS = TimeUnit.MINUTES.toMillis(5);
private static final Map<UUID, DropAttribution> itemDropAttributions = new ConcurrentHashMap<>();
private static class DropAttribution {
private final String user;
private final long expiresAt;
private DropAttribution(String user, long expiresAt) {
this.user = user;
this.expiresAt = expiresAt;
}
}
public static void playerDropItem(Location location, String user, ItemStack itemStack) {
if (!Config.getConfig(location.getWorld()).ITEM_DROPS || itemStack == null) {
return;
@@ -34,10 +51,46 @@ public final class PlayerDropItemListener extends Queue implements Listener {
Queue.queueItemTransaction(user, location.clone(), time, 0, itemId);
}
public static String getDroppedItemUser(UUID itemId) {
if (itemId == null) {
return null;
}
long timestamp = System.currentTimeMillis();
clearExpiredAttributions(timestamp);
DropAttribution attribution = itemDropAttributions.get(itemId);
if (attribution == null) {
return null;
}
if (attribution.expiresAt < timestamp) {
itemDropAttributions.remove(itemId);
return null;
}
return attribution.user;
}
private static void trackDroppedItem(Item item, String user) {
if (item == null || user == null || user.isEmpty()) {
return;
}
long timestamp = System.currentTimeMillis();
clearExpiredAttributions(timestamp);
itemDropAttributions.put(item.getUniqueId(), new DropAttribution(user, timestamp + ITEM_DROP_ATTRIBUTION_MS));
}
private static void clearExpiredAttributions(long timestamp) {
itemDropAttributions.entrySet().removeIf(entry -> entry.getValue().expiresAt < timestamp);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
protected void onPlayerDropItem(PlayerDropItemEvent event) {
Item item = event.getItemDrop();
ItemStack itemStack = item.getItemStack();
trackDroppedItem(item, event.getPlayer().getName());
playerDropItem(item.getLocation(), event.getPlayer().getName(), itemStack);
}