forked from github-mirror/CoreProtect
Next-generation sand/gravel logging (fixes #762)
- Sand/gravel that breaks (e.g. landing on a torch) no longer logs a phantom placement. - Falls now log at the actual landing coord, even when blocks like torches or grass are in the column. - Naturally-triggered falls (mobs, world gen, plugins, explosions) are now logged. - Falls caused by a player breaking the support are now attributed to the breaker at the real landing coord. - Falls without a player cause are now attributed to a new #gravity tag. - Rollback and restore of sand/gravel falls are now symmetric, leaving no phantom blocks in either direction.
This commit is contained in:
1 parent
0d47338038
commit
4ae0affe4b
8 files changed
+181
-130
No files matched your search
@@ -248,20 +248,6 @@ public class Queue {
|
||||
}, blockLocation.getLocation(), ticks);
|
||||
}
|
||||
|
||||
protected static void queueBlockGravityValidate(final String user, final Location location, final Block block, final Material blockType, int ticks) {
|
||||
Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> {
|
||||
try {
|
||||
Block placementBlock = BlockUtil.gravityScan(location, blockType, user);
|
||||
if (!block.equals(placementBlock)) {
|
||||
queueBlockPlace(user, placementBlock.getState(), blockType, null, blockType, -1, 0, null);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, location, ticks);
|
||||
}
|
||||
|
||||
protected static void queueContainerBreak(String user, Location location, Material type, ItemStack[] oldInventory) {
|
||||
int currentConsumer = Consumer.currentConsumer;
|
||||
int consumerId = Consumer.newConsumerId(currentConsumer);
|
||||
|
||||
@@ -29,6 +29,7 @@ import net.coreprotect.listener.entity.EntityDeathListener;
|
||||
import net.coreprotect.listener.entity.EntityExplodeListener;
|
||||
import net.coreprotect.listener.entity.EntityInteractListener;
|
||||
import net.coreprotect.listener.entity.EntityPickupItemListener;
|
||||
import net.coreprotect.listener.entity.EntitySpawnListener;
|
||||
import net.coreprotect.listener.entity.HangingBreakByEntityListener;
|
||||
import net.coreprotect.listener.entity.HangingBreakListener;
|
||||
import net.coreprotect.listener.entity.HangingPlaceListener;
|
||||
@@ -131,6 +132,7 @@ public final class ListenerHandler {
|
||||
pluginManager.registerEvents(new EntityExplodeListener(), plugin);
|
||||
pluginManager.registerEvents(new EntityInteractListener(), plugin);
|
||||
pluginManager.registerEvents(new EntityPickupItemListener(), plugin);
|
||||
pluginManager.registerEvents(new EntitySpawnListener(), plugin);
|
||||
pluginManager.registerEvents(new HangingPlaceListener(), plugin);
|
||||
pluginManager.registerEvents(new HangingBreakListener(), plugin);
|
||||
pluginManager.registerEvents(new HangingBreakByEntityListener(), plugin);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package net.coreprotect.listener.block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
@@ -38,7 +36,9 @@ import net.coreprotect.consumer.Queue;
|
||||
import net.coreprotect.database.Database;
|
||||
import net.coreprotect.model.BlockGroup;
|
||||
import net.coreprotect.paper.PaperAdapter;
|
||||
import net.coreprotect.thread.CacheHandler;
|
||||
import net.coreprotect.utility.BlockUtils;
|
||||
import net.coreprotect.utility.WorldUtils;
|
||||
|
||||
public final class BlockBreakListener extends Queue implements Listener {
|
||||
|
||||
@@ -86,7 +86,6 @@ public final class BlockBreakListener extends Queue implements Listener {
|
||||
}
|
||||
|
||||
protected static void processBlockBreak(Player player, String user, Block block, boolean logBreak, int skipScan) {
|
||||
List<Block> placementMap = new ArrayList<>();
|
||||
Material type = block.getType();
|
||||
World world = block.getWorld();
|
||||
int x = block.getX();
|
||||
@@ -124,24 +123,9 @@ public final class BlockBreakListener extends Queue implements Listener {
|
||||
Location scanLocation = locationMap[scanMin - 1];
|
||||
Block scanBlock = world.getBlockAt(scanLocation);
|
||||
Material scanType = scanBlock.getType();
|
||||
if (scanMin == 5) {
|
||||
if (scanType.hasGravity() || BukkitAdapter.ADAPTER.isSuspiciousBlock(scanType)) {
|
||||
if (Config.getConfig(world).BLOCK_MOVEMENT) {
|
||||
// log the top-most sand/gravel block as being removed
|
||||
int scanY = y + 2;
|
||||
boolean topFound = false;
|
||||
while (!topFound) {
|
||||
Block topBlock = world.getBlockAt(x, scanY, z);
|
||||
Material topMaterial = topBlock.getType();
|
||||
if (!topMaterial.hasGravity() && !BukkitAdapter.ADAPTER.isSuspiciousBlock(topMaterial)) {
|
||||
scanLocation = new Location(world, x, (scanY - 1), z);
|
||||
topFound = true;
|
||||
}
|
||||
scanY++;
|
||||
}
|
||||
placementMap.add(scanBlock);
|
||||
}
|
||||
}
|
||||
if (scanMin == 5 && (scanType.hasGravity() || BukkitAdapter.ADAPTER.isSuspiciousBlock(scanType)) && Config.getConfig(world).BLOCK_MOVEMENT) {
|
||||
// FallingBlock listeners read lookupCache to attribute the chain reaction; overwrite the cache up the gravity stack so falls record under whoever broke this block instead of #gravity or the original placer.
|
||||
seedGravityFallAttribution(user, world, x, z, y + 1, scanType);
|
||||
}
|
||||
if (!BlockGroup.TRACK_ANY.contains(scanType)) {
|
||||
if (scanMin != 5 && scanMin != 6 && !scanDown) { // side block
|
||||
@@ -208,11 +192,6 @@ public final class BlockBreakListener extends Queue implements Listener {
|
||||
log = true;
|
||||
}
|
||||
}
|
||||
else if (scanMin == 5) {
|
||||
if (scanType.hasGravity() || BukkitAdapter.ADAPTER.isSuspiciousBlock(scanType)) {
|
||||
log = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -323,13 +302,6 @@ public final class BlockBreakListener extends Queue implements Listener {
|
||||
|
||||
scanMin++;
|
||||
}
|
||||
|
||||
for (Block placementBlock : placementMap) {
|
||||
Material placementType = placementBlock.getType();
|
||||
if (placementType.hasGravity()) {
|
||||
queueBlockPlace(user, block.getState(), placementType, null, null, -1, 0, placementBlock.getBlockData().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
@@ -337,7 +309,27 @@ public final class BlockBreakListener extends Queue implements Listener {
|
||||
if (!event.isCancelled()) {
|
||||
String user = event.getPlayer().getName();
|
||||
Block block = event.getBlock();
|
||||
processBlockBreak(event.getPlayer(), user, event.getBlock(), Config.getConfig(block.getWorld()).BLOCK_BREAK, BlockUtil.NONE);
|
||||
processBlockBreak(event.getPlayer(), user, block, Config.getConfig(block.getWorld()).BLOCK_BREAK, BlockUtil.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void seedGravityFallAttribution(String user, World world, int x, int z, int startY, Material startType) {
|
||||
int worldId = WorldUtils.getWorldId(world.getName());
|
||||
int timestamp = (int) (System.currentTimeMillis() / 1000L);
|
||||
int worldMax = world.getMaxHeight();
|
||||
Material currentType = startType;
|
||||
int scanY = startY;
|
||||
while (scanY < worldMax) {
|
||||
String coordKey = x + "." + scanY + "." + z + "." + worldId;
|
||||
CacheHandler.lookupCache.put(coordKey, new Object[] { timestamp, user, currentType });
|
||||
scanY++;
|
||||
if (scanY >= worldMax) {
|
||||
break;
|
||||
}
|
||||
currentType = world.getBlockAt(x, scanY, z).getType();
|
||||
if (!currentType.hasGravity() && !BukkitAdapter.ADAPTER.isSuspiciousBlock(currentType)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,29 +79,6 @@ public final class BlockExplodeListener extends Queue implements Listener {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (scanType.hasGravity() && Config.getConfig(world).BLOCK_MOVEMENT) {
|
||||
// log the top-most sand/gravel block as being removed
|
||||
int scanY = location.getBlockY() + 1;
|
||||
boolean topFound = false;
|
||||
while (!topFound) {
|
||||
Block topBlock = world.getBlockAt(location.getBlockX(), scanY, location.getBlockZ());
|
||||
Material topMaterial = topBlock.getType();
|
||||
if (!topMaterial.hasGravity()) {
|
||||
location = new Location(world, location.getBlockX(), (scanY - 1), location.getBlockZ());
|
||||
topFound = true;
|
||||
|
||||
// log block attached to top as being removed
|
||||
if (BlockGroup.TRACK_ANY.contains(topMaterial) || BlockGroup.TRACK_TOP.contains(topMaterial) || BlockGroup.TRACK_TOP_BOTTOM.contains(topMaterial)) {
|
||||
blockMap.put(topBlock.getLocation(), topBlock);
|
||||
}
|
||||
}
|
||||
scanY++;
|
||||
}
|
||||
|
||||
Block gravityBlock = location.getBlock();
|
||||
blockMap.put(location, gravityBlock);
|
||||
Queue.queueBlockGravityValidate(user, location, gravityBlock, scanType, 0);
|
||||
}
|
||||
}
|
||||
scanMin++;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@ import net.coreprotect.config.Config;
|
||||
import net.coreprotect.consumer.Queue;
|
||||
import net.coreprotect.model.BlockGroup;
|
||||
import net.coreprotect.paper.PaperAdapter;
|
||||
import net.coreprotect.thread.CacheHandler;
|
||||
import net.coreprotect.utility.BlockUtils;
|
||||
import net.coreprotect.utility.MaterialUtils;
|
||||
import net.coreprotect.utility.WorldUtils;
|
||||
|
||||
public final class BlockPlaceListener extends Queue implements Listener {
|
||||
|
||||
@@ -38,12 +40,9 @@ public final class BlockPlaceListener extends Queue implements Listener {
|
||||
if (!event.isCancelled() && Config.getConfig(world).BLOCK_PLACE) {
|
||||
Player player = event.getPlayer();
|
||||
Block blockPlaced = event.getBlockPlaced();
|
||||
Block blockLogged = blockPlaced;
|
||||
String bBlockData = null;
|
||||
BlockState blockReplaced = event.getBlockReplacedState();
|
||||
Material blockType = blockPlaced.getType();
|
||||
Material forceType = null;
|
||||
int forceData = -1;
|
||||
boolean abort = false;
|
||||
|
||||
if (blockType == Material.LECTERN && blockReplaced.getType() == Material.LECTERN) {
|
||||
@@ -57,7 +56,7 @@ public final class BlockPlaceListener extends Queue implements Listener {
|
||||
bBlockData = waterlogged.getAsString();
|
||||
blockReplaced = null;
|
||||
}
|
||||
Queue.queueBlockPlaceDelayed(player.getName(), blockLogged.getLocation(), blockLogged.getType(), bBlockData, blockReplaced, 0);
|
||||
Queue.queueBlockPlaceDelayed(player.getName(), blockPlaced.getLocation(), blockPlaced.getType(), bBlockData, blockReplaced, 0);
|
||||
abort = true;
|
||||
}
|
||||
else if (BlockGroup.FIRE.contains(blockType)) {
|
||||
@@ -78,15 +77,7 @@ public final class BlockPlaceListener extends Queue implements Listener {
|
||||
}
|
||||
|
||||
if (!abort) {
|
||||
if (Config.getConfig(world).BLOCK_MOVEMENT) {
|
||||
blockLogged = BlockUtil.gravityScan(blockLogged.getLocation(), blockLogged.getType(), player.getName());
|
||||
if (!blockLogged.equals(blockPlaced)) {
|
||||
forceType = blockType;
|
||||
blockReplaced = blockLogged.getState();
|
||||
}
|
||||
}
|
||||
|
||||
BlockData blockData = blockLogged.getBlockData();
|
||||
BlockData blockData = blockPlaced.getBlockData();
|
||||
Waterlogged waterlogged = BlockUtils.checkWaterlogged(blockData, blockReplaced);
|
||||
if (waterlogged != null) {
|
||||
bBlockData = waterlogged.getAsString();
|
||||
@@ -94,7 +85,7 @@ public final class BlockPlaceListener extends Queue implements Listener {
|
||||
}
|
||||
|
||||
// fix for placed bisected blocks randomly returning the top or bottom of the block in this event
|
||||
BlockState blockState = blockLogged.getState();
|
||||
BlockState blockState = blockPlaced.getState();
|
||||
if (blockState.getBlockData() instanceof Bisected && !(blockState.getBlockData() instanceof Stairs || blockState.getBlockData() instanceof TrapDoor)) {
|
||||
if (((Bisected) blockState.getBlockData()).getHalf().equals(Half.TOP)) {
|
||||
if (blockPlaced.getY() > BukkitAdapter.ADAPTER.getMinHeight(world)) {
|
||||
@@ -103,7 +94,15 @@ public final class BlockPlaceListener extends Queue implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
Queue.queueBlockPlace(player.getName(), blockState, blockPlaced.getType(), blockReplaced, forceType, forceData, 0, bBlockData);
|
||||
if (blockType.hasGravity()) {
|
||||
// FallingBlock listeners read lookupCache before the async consumer can populate it; record the placer synchronously so the fall and landing get attributed to the player instead of #gravity.
|
||||
int worldId = WorldUtils.getWorldId(world.getName());
|
||||
int timestamp = (int) (System.currentTimeMillis() / 1000L);
|
||||
String coordKey = blockPlaced.getX() + "." + blockPlaced.getY() + "." + blockPlaced.getZ() + "." + worldId;
|
||||
CacheHandler.lookupCache.put(coordKey, new Object[] { timestamp, player.getName(), blockType });
|
||||
}
|
||||
|
||||
Queue.queueBlockPlace(player.getName(), blockState, blockPlaced.getType(), blockReplaced, null, -1, 0, bBlockData);
|
||||
|
||||
if (BukkitAdapter.ADAPTER.isSign(blockType)) {
|
||||
if (Config.getConfig(world).SIGN_TEXT) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.EnderDragon;
|
||||
import org.bukkit.entity.Enderman;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Fox;
|
||||
import org.bukkit.entity.Ravager;
|
||||
import org.bukkit.entity.Silverfish;
|
||||
@@ -19,59 +20,115 @@ import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
|
||||
import net.coreprotect.config.Config;
|
||||
import net.coreprotect.consumer.Queue;
|
||||
import net.coreprotect.thread.CacheHandler;
|
||||
import net.coreprotect.utility.WorldUtils;
|
||||
|
||||
public final class EntityChangeBlockListener extends Queue implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
protected void onEntityChangeBlock(EntityChangeBlockEvent event) {
|
||||
World world = event.getBlock().getWorld();
|
||||
if (!event.isCancelled() && Config.getConfig(world).ENTITY_CHANGE) {
|
||||
Entity entity = event.getEntity(); // Can be sand/gravel
|
||||
Block block = event.getBlock();
|
||||
Material newtype = event.getTo();
|
||||
Material type = event.getBlock().getType();
|
||||
String e = "";
|
||||
if (entity instanceof Enderman) {
|
||||
e = "#enderman";
|
||||
if (event.isCancelled() || !Config.getConfig(world).ENTITY_CHANGE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity entity = event.getEntity();
|
||||
Block block = event.getBlock();
|
||||
Material newtype = event.getTo();
|
||||
Material type = event.getBlock().getType();
|
||||
|
||||
if (entity instanceof FallingBlock) {
|
||||
handleFallingBlock(event, (FallingBlock) entity, block, newtype, type, world);
|
||||
return;
|
||||
}
|
||||
|
||||
String e = "";
|
||||
if (entity instanceof Enderman) {
|
||||
e = "#enderman";
|
||||
}
|
||||
else if (entity instanceof EnderDragon) {
|
||||
e = "#enderdragon";
|
||||
}
|
||||
else if (entity instanceof Fox) {
|
||||
e = "#fox";
|
||||
}
|
||||
else if (entity instanceof Wither) {
|
||||
e = "#wither";
|
||||
}
|
||||
else if (entity instanceof Turtle) {
|
||||
e = "#turtle";
|
||||
}
|
||||
else if (entity instanceof Ravager) {
|
||||
e = "#ravager";
|
||||
}
|
||||
else if (entity instanceof Zombie) {
|
||||
e = "#zombie";
|
||||
}
|
||||
else if (entity instanceof Silverfish) {
|
||||
if (newtype.equals(Material.AIR) || newtype.equals(Material.CAVE_AIR)) {
|
||||
e = "#silverfish";
|
||||
}
|
||||
else if (entity instanceof EnderDragon) {
|
||||
e = "#enderdragon";
|
||||
}
|
||||
else if (entity.getType().name().equals("WIND_CHARGE")) {
|
||||
e = "#windcharge";
|
||||
}
|
||||
else if (entity.getType().name().equals("BREEZE_WIND_CHARGE")) {
|
||||
e = "#breezewindcharge";
|
||||
}
|
||||
if (e.length() > 0) {
|
||||
if (newtype.equals(Material.AIR) || newtype.equals(Material.CAVE_AIR)) {
|
||||
Queue.queueBlockBreak(e, block.getState(), type, block.getBlockData().getAsString(), 0);
|
||||
}
|
||||
else if (entity instanceof Fox) {
|
||||
e = "#fox";
|
||||
}
|
||||
else if (entity instanceof Wither) {
|
||||
e = "#wither";
|
||||
}
|
||||
else if (entity instanceof Turtle) {
|
||||
e = "#turtle";
|
||||
}
|
||||
else if (entity instanceof Ravager) {
|
||||
e = "#ravager";
|
||||
}
|
||||
else if (entity instanceof Zombie) {
|
||||
e = "#zombie";
|
||||
}
|
||||
else if (entity instanceof Silverfish) {
|
||||
if (newtype.equals(Material.AIR) || newtype.equals(Material.CAVE_AIR)) {
|
||||
e = "#silverfish";
|
||||
}
|
||||
}
|
||||
else if (entity.getType().name().equals("WIND_CHARGE")) {
|
||||
e = "#windcharge";
|
||||
}
|
||||
else if (entity.getType().name().equals("BREEZE_WIND_CHARGE")) {
|
||||
e = "#breezewindcharge";
|
||||
}
|
||||
if (e.length() > 0) {
|
||||
if (newtype.equals(Material.AIR) || newtype.equals(Material.CAVE_AIR)) {
|
||||
Queue.queueBlockBreak(e, block.getState(), type, block.getBlockData().getAsString(), 0);
|
||||
}
|
||||
else {
|
||||
queueBlockPlace(e, block.getState(), type, block.getState(), newtype, -1, 0, event.getBlockData().getAsString());
|
||||
}
|
||||
else {
|
||||
queueBlockPlace(e, block.getState(), type, block.getState(), newtype, -1, 0, event.getBlockData().getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFallingBlock(EntityChangeBlockEvent event, FallingBlock fallingBlock, Block block, Material newtype, Material type, World world) {
|
||||
int worldId = WorldUtils.getWorldId(world.getName());
|
||||
|
||||
if (newtype.equals(Material.AIR) || newtype.equals(Material.CAVE_AIR)) {
|
||||
if (!Config.getConfig(world).BLOCK_BREAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
String coordKey = block.getX() + "." + block.getY() + "." + block.getZ() + "." + worldId;
|
||||
String user = lookupCachedUser(coordKey, type);
|
||||
if (user == null) {
|
||||
user = "#gravity";
|
||||
}
|
||||
|
||||
Queue.queueBlockBreak(user, block.getState(), type, block.getBlockData().getAsString(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Config.getConfig(world).BLOCK_PLACE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] originData = CacheHandler.fallingBlockSpawnCache.remove(fallingBlock.getUniqueId().toString());
|
||||
String user = "#gravity";
|
||||
if (originData != null) {
|
||||
String originKey = (String) originData[1];
|
||||
String lookupUser = lookupCachedUser(originKey, fallingBlock.getBlockData().getMaterial());
|
||||
if (lookupUser != null) {
|
||||
user = lookupUser;
|
||||
}
|
||||
}
|
||||
|
||||
queueBlockPlace(user, block.getState(), type, block.getState(), newtype, -1, 0, event.getBlockData().getAsString());
|
||||
}
|
||||
|
||||
private static String lookupCachedUser(String coordKey, Material expectedType) {
|
||||
Object[] data = CacheHandler.lookupCache.get(coordKey);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
if (expectedType != null && data[2] instanceof Material && !data[2].equals(expectedType)) {
|
||||
return null;
|
||||
}
|
||||
return (String) data[1];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.coreprotect.listener.entity;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||
|
||||
import net.coreprotect.thread.CacheHandler;
|
||||
import net.coreprotect.utility.WorldUtils;
|
||||
|
||||
public final class EntitySpawnListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
protected void onEntitySpawn(EntitySpawnEvent event) {
|
||||
if (event.getEntityType() != EntityType.FALLING_BLOCK) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = event.getLocation();
|
||||
if (location.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int worldId = WorldUtils.getWorldId(location.getWorld().getName());
|
||||
String originKey = location.getBlockX() + "." + location.getBlockY() + "." + location.getBlockZ() + "." + worldId;
|
||||
int timestamp = (int) (System.currentTimeMillis() / 1000L);
|
||||
|
||||
CacheHandler.fallingBlockSpawnCache.put(event.getEntity().getUniqueId().toString(), new Object[] { timestamp, originKey });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ public class CacheHandler implements Runnable {
|
||||
public static ConcurrentHashMap<String, Object[]> bonemealDuplicateCache = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
public static ConcurrentHashMap<String, Object[]> entityKillDuplicateCache = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
public static ConcurrentHashMap<String, Object[]> redstoneCache = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
public static ConcurrentHashMap<String, Object[]> fallingBlockSpawnCache = new ConcurrentHashMap<>(16, 0.75f, 2);
|
||||
|
||||
public static String locationKey(Location location) {
|
||||
if (location == null || location.getWorld() == null) {
|
||||
@@ -63,7 +64,7 @@ public class CacheHandler implements Runnable {
|
||||
public void run() {
|
||||
while (ConfigHandler.serverRunning) {
|
||||
try {
|
||||
for (int id = 0; id < 13; id++) {
|
||||
for (int id = 0; id < 14; id++) {
|
||||
Thread.sleep(1000);
|
||||
int scanTime = 30;
|
||||
Map cache = CacheHandler.lookupCache;
|
||||
@@ -116,6 +117,10 @@ public class CacheHandler implements Runnable {
|
||||
cache = CacheHandler.entityKillDuplicateCache;
|
||||
scanTime = 900; // 15 minutes
|
||||
break;
|
||||
case 13:
|
||||
cache = CacheHandler.fallingBlockSpawnCache;
|
||||
scanTime = 30; // 30 seconds
|
||||
break;
|
||||
}
|
||||
|
||||
int timestamp = (int) (System.currentTimeMillis() / 1000L) - scanTime;
|
||||
|
||||
Reference in new issue
Block a user