forked from github-mirror/CoreProtect
Added logging for dropping items into a hopper
This commit is contained in:
1 parent
829bcc530d
commit
cdc8082c3e
3 files changed
+256
-90
No files matched your search
@@ -53,6 +53,9 @@ public class ContainerLogger extends Queue {
|
|||||||
else if (type == Material.JUKEBOX || type == Material.ARMOR_STAND) {
|
else if (type == Material.JUKEBOX || type == Material.ARMOR_STAND) {
|
||||||
contents = (ItemStack[]) ((Object[]) container)[1];
|
contents = (ItemStack[]) ((Object[]) container)[1];
|
||||||
}
|
}
|
||||||
|
else if (container instanceof ItemStack[]) {
|
||||||
|
contents = (ItemStack[]) container;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
Inventory inventory = (Inventory) container;
|
Inventory inventory = (Inventory) container;
|
||||||
if (inventory != null) {
|
if (inventory != null) {
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
import org.bukkit.block.BlockState;
|
||||||
import org.bukkit.block.DoubleChest;
|
import org.bukkit.block.DoubleChest;
|
||||||
|
import org.bukkit.block.Hopper;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
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.InventoryClickEvent;
|
||||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.inventory.BlockInventoryHolder;
|
import org.bukkit.inventory.BlockInventoryHolder;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
@@ -139,96 +142,7 @@ public final class InventoryChangeListener extends Queue implements Listener {
|
|||||||
inventoryData = inventory.getContents();
|
inventoryData = inventory.getContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = playerLocation.getBlockX();
|
return queueContainerTransaction(user, playerLocation, type, inventory, inventoryData, null);
|
||||||
int y = playerLocation.getBlockY();
|
|
||||||
int z = playerLocation.getBlockZ();
|
|
||||||
|
|
||||||
String transactingChestId = playerLocation.getWorld().getUID().toString() + "." + x + "." + y + "." + z;
|
|
||||||
String loggingChestId = user.toLowerCase(Locale.ROOT) + "." + x + "." + y + "." + z;
|
|
||||||
for (String loggingChestIdViewer : ConfigHandler.oldContainer.keySet()) {
|
|
||||||
if (loggingChestIdViewer.equals(loggingChestId) || !loggingChestIdViewer.endsWith("." + x + "." + y + "." + z)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigHandler.oldContainer.get(loggingChestIdViewer) != null) { // player has pending consumer item
|
|
||||||
int sizeOld = ConfigHandler.oldContainer.get(loggingChestIdViewer).size();
|
|
||||||
ConfigHandler.forceContainer.computeIfAbsent(loggingChestIdViewer, k -> new ArrayList<>());
|
|
||||||
List<ItemStack[]> list = ConfigHandler.forceContainer.get(loggingChestIdViewer);
|
|
||||||
|
|
||||||
if (list != null && list.size() < sizeOld) {
|
|
||||||
ItemStack[] containerState = ItemUtils.getContainerState(inventoryData);
|
|
||||||
|
|
||||||
// If items have been removed by a hopper, merge into containerState
|
|
||||||
List<Object> transactingChest = ConfigHandler.transactingChest.get(transactingChestId);
|
|
||||||
if (transactingChest != null) {
|
|
||||||
List<Object> transactingChestList = Collections.synchronizedList(new ArrayList<>(transactingChest));
|
|
||||||
if (!transactingChestList.isEmpty()) {
|
|
||||||
ItemStack[] newState = new ItemStack[containerState.length + transactingChestList.size()];
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (int j = 0; j < containerState.length; j++) {
|
|
||||||
newState[j] = containerState[j];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Object item : transactingChestList) {
|
|
||||||
ItemStack addItem = null;
|
|
||||||
ItemStack removeItem = null;
|
|
||||||
if (item instanceof ItemStack) {
|
|
||||||
addItem = (ItemStack) item;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
addItem = ((ItemStack[]) item)[0];
|
|
||||||
removeItem = ((ItemStack[]) item)[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// item was removed by hopper, add back to state
|
|
||||||
if (addItem != null) {
|
|
||||||
newState[count] = addItem;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// item was added by hopper, remove from state
|
|
||||||
if (removeItem != null) {
|
|
||||||
for (ItemStack check : newState) {
|
|
||||||
if (check != null && check.isSimilar(removeItem)) {
|
|
||||||
check.setAmount(check.getAmount() - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
containerState = newState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modifyForceContainer(loggingChestIdViewer, containerState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int chestId = getChestId(loggingChestId);
|
|
||||||
if (chestId > 0) {
|
|
||||||
List<ItemStack[]> forceList = ConfigHandler.forceContainer.get(loggingChestId);
|
|
||||||
if (forceList != null) {
|
|
||||||
int forceSize = forceList.size();
|
|
||||||
List<ItemStack[]> list = ConfigHandler.oldContainer.get(loggingChestId);
|
|
||||||
|
|
||||||
if (list != null && list.size() <= forceSize) {
|
|
||||||
list.add(ItemUtils.getContainerState(inventoryData));
|
|
||||||
ConfigHandler.oldContainer.put(loggingChestId, list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
List<ItemStack[]> list = new ArrayList<>();
|
|
||||||
list.add(ItemUtils.getContainerState(inventoryData));
|
|
||||||
ConfigHandler.oldContainer.put(loggingChestId, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigHandler.transactingChest.computeIfAbsent(transactingChestId, k -> Collections.synchronizedList(new ArrayList<>()));
|
|
||||||
Queue.queueContainerTransaction(user, playerLocation, type, inventory, chestId);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,6 +150,103 @@ public final class InventoryChangeListener extends Queue implements Listener {
|
|||||||
return false;
|
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();
|
||||||
|
|
||||||
|
String transactingChestId = playerLocation.getWorld().getUID().toString() + "." + x + "." + y + "." + z;
|
||||||
|
String loggingChestId = user.toLowerCase(Locale.ROOT) + "." + x + "." + y + "." + z;
|
||||||
|
for (String loggingChestIdViewer : ConfigHandler.oldContainer.keySet()) {
|
||||||
|
if (loggingChestIdViewer.equals(loggingChestId) || !loggingChestIdViewer.endsWith("." + x + "." + y + "." + z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ConfigHandler.oldContainer.get(loggingChestIdViewer) != null) { // player has pending consumer item
|
||||||
|
int sizeOld = ConfigHandler.oldContainer.get(loggingChestIdViewer).size();
|
||||||
|
ConfigHandler.forceContainer.computeIfAbsent(loggingChestIdViewer, k -> new ArrayList<>());
|
||||||
|
List<ItemStack[]> list = ConfigHandler.forceContainer.get(loggingChestIdViewer);
|
||||||
|
|
||||||
|
if (list != null && list.size() < sizeOld) {
|
||||||
|
ItemStack[] containerState = ItemUtils.getContainerState(inventoryData);
|
||||||
|
|
||||||
|
// If items have been removed by a hopper, merge into containerState
|
||||||
|
List<Object> transactingChest = ConfigHandler.transactingChest.get(transactingChestId);
|
||||||
|
if (transactingChest != null) {
|
||||||
|
List<Object> transactingChestList = Collections.synchronizedList(new ArrayList<>(transactingChest));
|
||||||
|
if (!transactingChestList.isEmpty()) {
|
||||||
|
ItemStack[] newState = new ItemStack[containerState.length + transactingChestList.size()];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < containerState.length; j++) {
|
||||||
|
newState[j] = containerState[j];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object item : transactingChestList) {
|
||||||
|
ItemStack addItem = null;
|
||||||
|
ItemStack removeItem = null;
|
||||||
|
if (item instanceof ItemStack) {
|
||||||
|
addItem = (ItemStack) item;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addItem = ((ItemStack[]) item)[0];
|
||||||
|
removeItem = ((ItemStack[]) item)[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// item was removed by hopper, add back to state
|
||||||
|
if (addItem != null) {
|
||||||
|
newState[count] = addItem;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// item was added by hopper, remove from state
|
||||||
|
if (removeItem != null) {
|
||||||
|
for (ItemStack check : newState) {
|
||||||
|
if (check != null && check.isSimilar(removeItem)) {
|
||||||
|
check.setAmount(check.getAmount() - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerState = newState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyForceContainer(loggingChestIdViewer, containerState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int chestId = getChestId(loggingChestId);
|
||||||
|
if (chestId > 0) {
|
||||||
|
List<ItemStack[]> forceList = ConfigHandler.forceContainer.get(loggingChestId);
|
||||||
|
if (forceList != null) {
|
||||||
|
int forceSize = forceList.size();
|
||||||
|
List<ItemStack[]> list = ConfigHandler.oldContainer.get(loggingChestId);
|
||||||
|
|
||||||
|
if (list != null && list.size() <= forceSize) {
|
||||||
|
list.add(ItemUtils.getContainerState(inventoryData));
|
||||||
|
ConfigHandler.oldContainer.put(loggingChestId, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<ItemStack[]> list = new ArrayList<>();
|
||||||
|
list.add(ItemUtils.getContainerState(inventoryData));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static void onInventoryInteractAsync(Player player, Inventory inventory, boolean enderChest) {
|
static void onInventoryInteractAsync(Player player, Inventory inventory, boolean enderChest) {
|
||||||
if (inventory == null) {
|
if (inventory == null) {
|
||||||
return;
|
return;
|
||||||
@@ -542,6 +553,105 @@ public final class InventoryChangeListener extends Queue implements Listener {
|
|||||||
HopperPullListener.processHopperPull(location, "#hopper", sourceHolder, destinationHolder, event.getItem());
|
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) {
|
private boolean isAdvancedChest(Inventory inventory) {
|
||||||
return CoreProtect.getInstance().isAdvancedChestsEnabled() && AdvancedChestsAPI.getInventoryManager().getAdvancedChest(inventory) != null;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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.Location;
|
||||||
import org.bukkit.entity.Item;
|
import org.bukkit.entity.Item;
|
||||||
@@ -18,6 +22,19 @@ import net.coreprotect.consumer.Queue;
|
|||||||
|
|
||||||
public final class PlayerDropItemListener extends Queue implements Listener {
|
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) {
|
public static void playerDropItem(Location location, String user, ItemStack itemStack) {
|
||||||
if (!Config.getConfig(location.getWorld()).ITEM_DROPS || itemStack == null) {
|
if (!Config.getConfig(location.getWorld()).ITEM_DROPS || itemStack == null) {
|
||||||
return;
|
return;
|
||||||
@@ -34,10 +51,46 @@ public final class PlayerDropItemListener extends Queue implements Listener {
|
|||||||
Queue.queueItemTransaction(user, location.clone(), time, 0, itemId);
|
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)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
protected void onPlayerDropItem(PlayerDropItemEvent event) {
|
protected void onPlayerDropItem(PlayerDropItemEvent event) {
|
||||||
Item item = event.getItemDrop();
|
Item item = event.getItemDrop();
|
||||||
ItemStack itemStack = item.getItemStack();
|
ItemStack itemStack = item.getItemStack();
|
||||||
|
trackDroppedItem(item, event.getPlayer().getName());
|
||||||
playerDropItem(item.getLocation(), event.getPlayer().getName(), itemStack);
|
playerDropItem(item.getLocation(), event.getPlayer().getName(), itemStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user