Improved performance of BlockPreDispenseEvent
This commit is contained in:
parent
4803b1af23
commit
484614f71e
4 changed files with 161 additions and 2 deletions
|
|
@ -109,6 +109,8 @@ public class ConfigHandler extends Queue {
|
||||||
public static ConcurrentHashMap<String, List<ItemStack>> itemsBuy = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<String, List<ItemStack>> itemsBuy = new ConcurrentHashMap<>();
|
||||||
public static ConcurrentHashMap<String, Object[]> hopperAbort = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<String, Object[]> hopperAbort = new ConcurrentHashMap<>();
|
||||||
public static ConcurrentHashMap<String, Object[]> hopperSuccess = new ConcurrentHashMap<>();
|
public static ConcurrentHashMap<String, Object[]> hopperSuccess = new ConcurrentHashMap<>();
|
||||||
|
public static ConcurrentHashMap<String, ConcurrentHashMap<String, Long>> dispenserNoChange = new ConcurrentHashMap<>();
|
||||||
|
public static ConcurrentHashMap<String, Object[]> dispenserPending = new ConcurrentHashMap<>();
|
||||||
public static Map<String, List<ItemStack[]>> forceContainer = syncMap();
|
public static Map<String, List<ItemStack[]>> forceContainer = syncMap();
|
||||||
public static Map<String, Integer> lookupType = syncMap();
|
public static Map<String, Integer> lookupType = syncMap();
|
||||||
public static Map<String, Object[]> lookupThrottle = syncMap();
|
public static Map<String, Object[]> lookupThrottle = syncMap();
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
@ -65,6 +66,52 @@ public class ContainerLogger extends Queue {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this is a dispenser with no actual changes
|
||||||
|
if (player.equals("#dispenser") && ItemUtils.compareContainers(oldInventory, newInventory)) {
|
||||||
|
// No changes detected, mark this dispenser in the dispenserNoChange map
|
||||||
|
// Extract the location key from the loggingContainerId
|
||||||
|
// Format: #dispenser.x.y.z
|
||||||
|
String[] parts = loggingContainerId.split("\\.");
|
||||||
|
if (parts.length >= 4) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
|
||||||
|
// Create the location key
|
||||||
|
String locationKey = location.getWorld().getUID().toString() + "." + x + "." + y + "." + z;
|
||||||
|
|
||||||
|
// Check if we have pending event details for this dispenser
|
||||||
|
Object[] pendingEvent = ConfigHandler.dispenserPending.remove(locationKey);
|
||||||
|
if (pendingEvent != null) {
|
||||||
|
// We have the exact event details, use them to mark this event as unchanged
|
||||||
|
String eventKey = (String) pendingEvent[0];
|
||||||
|
|
||||||
|
// Get or create the inner map for this location
|
||||||
|
ConfigHandler.dispenserNoChange.computeIfAbsent(locationKey, k -> new ConcurrentHashMap<>()).put(eventKey, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here, the dispenser event resulted in changes
|
||||||
|
// Remove any pending event for this dispenser
|
||||||
|
if (player.equals("#dispenser")) {
|
||||||
|
String[] parts = loggingContainerId.split("\\.");
|
||||||
|
if (parts.length >= 4) {
|
||||||
|
int x = Integer.parseInt(parts[1]);
|
||||||
|
int y = Integer.parseInt(parts[2]);
|
||||||
|
int z = Integer.parseInt(parts[3]);
|
||||||
|
|
||||||
|
String locationKey = location.getWorld().getUID().toString() + "." + x + "." + y + "." + z;
|
||||||
|
|
||||||
|
// Remove the pending event since it resulted in changes
|
||||||
|
ConfigHandler.dispenserPending.remove(locationKey);
|
||||||
|
|
||||||
|
// Clear any existing dispenserNoChange entries for this location
|
||||||
|
ConfigHandler.dispenserNoChange.remove(locationKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<ItemStack[]> forceList = ConfigHandler.forceContainer.get(loggingContainerId);
|
List<ItemStack[]> forceList = ConfigHandler.forceContainer.get(loggingContainerId);
|
||||||
if (forceList != null) {
|
if (forceList != null) {
|
||||||
int forceSize = 0;
|
int forceSize = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package net.coreprotect.paper.listener;
|
package net.coreprotect.paper.listener;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
|
@ -13,6 +15,7 @@ import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import io.papermc.paper.event.block.BlockPreDispenseEvent;
|
import io.papermc.paper.event.block.BlockPreDispenseEvent;
|
||||||
import net.coreprotect.config.Config;
|
import net.coreprotect.config.Config;
|
||||||
|
import net.coreprotect.config.ConfigHandler;
|
||||||
import net.coreprotect.consumer.Queue;
|
import net.coreprotect.consumer.Queue;
|
||||||
import net.coreprotect.listener.player.InventoryChangeListener;
|
import net.coreprotect.listener.player.InventoryChangeListener;
|
||||||
|
|
||||||
|
|
@ -21,6 +24,9 @@ public final class BlockPreDispenseListener extends Queue implements Listener {
|
||||||
public static boolean useBlockPreDispenseEvent = true;
|
public static boolean useBlockPreDispenseEvent = true;
|
||||||
public static boolean useForDroppers = false;
|
public static boolean useForDroppers = false;
|
||||||
|
|
||||||
|
// Maximum time to keep entries in the cache (in milliseconds)
|
||||||
|
private static final long CACHE_EXPIRY_TIME = 5000; // 5 seconds
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
public void onBlockPreDispense(BlockPreDispenseEvent event) {
|
public void onBlockPreDispense(BlockPreDispenseEvent event) {
|
||||||
Block block = event.getBlock();
|
Block block = event.getBlock();
|
||||||
|
|
@ -35,10 +41,57 @@ public final class BlockPreDispenseListener extends Queue implements Listener {
|
||||||
useForDroppers = true;
|
useForDroppers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safeguard against null items
|
||||||
|
ItemStack item = event.getItemStack();
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a basic location key for this dispenser
|
||||||
|
String locationKey = block.getWorld().getUID().toString() + "." + block.getX() + "." + block.getY() + "." + block.getZ();
|
||||||
|
|
||||||
|
// Create a detailed event key that includes item details
|
||||||
|
String eventKey = event.getSlot() + "." + item.getType().name() + ":" + item.getAmount();
|
||||||
|
|
||||||
|
// Add metadata hash if available
|
||||||
|
if (item.hasItemMeta()) {
|
||||||
|
try {
|
||||||
|
eventKey += ":" + item.getItemMeta().hashCode();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// If we can't get metadata hash, just use the basic key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get or create the inner map for this location
|
||||||
|
ConcurrentHashMap<String, Long> locationMap = ConfigHandler.dispenserNoChange.computeIfAbsent(locationKey, k -> new ConcurrentHashMap<>());
|
||||||
|
|
||||||
|
// Check if this specific dispenser event has been marked as having no changes recently
|
||||||
|
Long lastNoChangeTime = locationMap.get(eventKey);
|
||||||
|
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (lastNoChangeTime != null && (currentTime - lastNoChangeTime) < CACHE_EXPIRY_TIME) {
|
||||||
|
// This specific dispenser event was recently processed and had no changes
|
||||||
|
// Update the timestamp to extend the skip period
|
||||||
|
locationMap.put(eventKey, currentTime);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a new or changed event
|
||||||
|
// Clear any existing dispenserNoChange entries for this location
|
||||||
|
ConfigHandler.dispenserNoChange.remove(locationKey);
|
||||||
|
|
||||||
|
// Store the event details for ContainerLogger to use
|
||||||
|
ConfigHandler.dispenserPending.put(locationKey, new Object[] { eventKey, // The detailed event key
|
||||||
|
currentTime, // Timestamp
|
||||||
|
event.getSlot(), // Slot
|
||||||
|
item.clone() // Item (cloned to prevent modification)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process the inventory transaction
|
||||||
String user = "#dispenser";
|
String user = "#dispenser";
|
||||||
ItemStack[] inventory = ((InventoryHolder) block.getState()).getInventory().getStorageContents();
|
ItemStack[] inventory = ((InventoryHolder) block.getState()).getInventory().getStorageContents();
|
||||||
InventoryChangeListener.inventoryTransaction(user, block.getLocation(), inventory);
|
InventoryChangeListener.inventoryTransaction(user, block.getLocation(), inventory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class CacheHandler implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
while (ConfigHandler.serverRunning) {
|
while (ConfigHandler.serverRunning) {
|
||||||
try {
|
try {
|
||||||
for (int id = 0; id < 8; id++) {
|
for (int id = 0; id < 9; id++) {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
int scanTime = 30;
|
int scanTime = 30;
|
||||||
Map cache = CacheHandler.lookupCache;
|
Map cache = CacheHandler.lookupCache;
|
||||||
|
|
@ -59,6 +59,10 @@ public class CacheHandler implements Runnable {
|
||||||
cache = ConfigHandler.entityBlockMapper;
|
cache = ConfigHandler.entityBlockMapper;
|
||||||
scanTime = 5;
|
scanTime = 5;
|
||||||
break;
|
break;
|
||||||
|
case 8:
|
||||||
|
// Clean up dispenserNoChange cache
|
||||||
|
cleanupDispenserCache();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int timestamp = (int) (System.currentTimeMillis() / 1000L) - scanTime;
|
int timestamp = (int) (System.currentTimeMillis() / 1000L) - scanTime;
|
||||||
|
|
@ -88,4 +92,57 @@ public class CacheHandler implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the dispenserNoChange cache by removing entries older than 5 seconds
|
||||||
|
*/
|
||||||
|
private void cleanupDispenserCache() {
|
||||||
|
try {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long expiryTime = 5000; // 5 seconds
|
||||||
|
|
||||||
|
// Clean up dispenserNoChange map (now a nested map)
|
||||||
|
Iterator<Entry<String, ConcurrentHashMap<String, Long>>> locationIterator = ConfigHandler.dispenserNoChange.entrySet().iterator();
|
||||||
|
while (locationIterator.hasNext()) {
|
||||||
|
Entry<String, ConcurrentHashMap<String, Long>> locationEntry = locationIterator.next();
|
||||||
|
ConcurrentHashMap<String, Long> eventMap = locationEntry.getValue();
|
||||||
|
|
||||||
|
if (eventMap.isEmpty()) {
|
||||||
|
// Remove empty location entries
|
||||||
|
locationIterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up expired events within this location
|
||||||
|
Iterator<Entry<String, Long>> eventIterator = eventMap.entrySet().iterator();
|
||||||
|
while (eventIterator.hasNext()) {
|
||||||
|
Entry<String, Long> eventEntry = eventIterator.next();
|
||||||
|
if ((currentTime - eventEntry.getValue()) > expiryTime) {
|
||||||
|
eventIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all events were removed, remove the location entry
|
||||||
|
if (eventMap.isEmpty()) {
|
||||||
|
locationIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up dispenserPending map
|
||||||
|
Iterator<Entry<String, Object[]>> pendingIterator = ConfigHandler.dispenserPending.entrySet().iterator();
|
||||||
|
while (pendingIterator.hasNext()) {
|
||||||
|
Entry<String, Object[]> entry = pendingIterator.next();
|
||||||
|
Object[] data = entry.getValue();
|
||||||
|
if (data != null && data.length > 1) {
|
||||||
|
long timestamp = (long) data[1];
|
||||||
|
if ((currentTime - timestamp) > expiryTime) {
|
||||||
|
pendingIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue