From e1e31beff09796670773a89a4468c5020df9577d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sun, 7 Jan 2018 21:25:49 +1100 Subject: [PATCH] Fixes #847 --- .../boydti/fawe/bukkit/v0/ChunkListener.java | 200 +++++++++--------- .../java/com/boydti/fawe/config/Settings.java | 2 +- 2 files changed, 106 insertions(+), 96 deletions(-) diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java index 67cd3183..0a664cb3 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/ChunkListener.java @@ -5,12 +5,12 @@ import com.boydti.fawe.bukkit.FaweBukkit; import com.boydti.fawe.config.Settings; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.TaskManager; -import com.sk89q.worldedit.blocks.BlockID; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -20,6 +20,8 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.entity.EntityChangeBlockEvent; import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import sun.misc.SharedSecrets; public class ChunkListener implements Listener { @@ -29,6 +31,14 @@ public class ChunkListener implements Listener { public ChunkListener() { if (Settings.IMP.TICK_LIMITER.ENABLED) { Bukkit.getPluginManager().registerEvents(ChunkListener.this, Fawe.imp().getPlugin()); + TaskManager.IMP.repeat(new Runnable() { + @Override + public void run() { + physSkip = 0; + physCancelPair = Long.MIN_VALUE; + physCancel = false; + } + }, 1); TaskManager.IMP.repeat(new Runnable() { @Override public void run() { @@ -82,104 +92,56 @@ public class ChunkListener implements Listener { } - private int lastPhysY = 0; + private int physSkip; + private boolean physCancel; + private long physCancelPair; - @EventHandler(priority = EventPriority.LOWEST) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPhysics(BlockPhysicsEvent event) { + if (physCancel) { + Block block = event.getBlock(); + long pair = MathMan.pairInt(block.getX() >> 4, block.getZ() >> 4); + if (physCancelPair == pair) { + event.setCancelled(true); + return; + } + if (badChunks.containsKey(pair)) { + physCancelPair = pair; + event.setCancelled(true); + return; + } + } if (physicsFreeze) { event.setCancelled(true); return; } - Block block = event.getBlock(); - int x = block.getX(); - int z = block.getZ(); - int cx = x >> 4; - int cz = z >> 4; - int[] count = getCount(cx, cz); - if (count[0] >= Settings.IMP.TICK_LIMITER.PHYSICS) { - event.setCancelled(true); - return; - } - int blockId = block.getTypeId(); - if (event.getChangedTypeId() == blockId) { - int y = block.getY(); - int tmpLastY = lastPhysY; - lastPhysY = y; - int amount; - switch (blockId) { - case BlockID.REDSTONE_BLOCK: - case BlockID.REDSTONE_LAMP_OFF: - case BlockID.REDSTONE_LAMP_ON: - case BlockID.REDSTONE_ORE: - case BlockID.REDSTONE_REPEATER_OFF: - case BlockID.REDSTONE_REPEATER_ON: - case BlockID.REDSTONE_TORCH_OFF: - case BlockID.REDSTONE_TORCH_ON: - case BlockID.REDSTONE_WIRE: - case BlockID.GLOWING_REDSTONE_ORE: - case BlockID.TRIPWIRE: - case BlockID.TRIPWIRE_HOOK: - case 218: // Observer - case BlockID.PISTON_BASE: - case BlockID.PISTON_STICKY_BASE: - case BlockID.IRON_DOOR: - case BlockID.ACACIA_DOOR: - case BlockID.BIRCH_DOOR: - case BlockID.DARK_OAK_DOOR: - case BlockID.IRON_TRAP_DOOR: - case BlockID.JUNGLE_DOOR: - case BlockID.SPRUCE_DOOR: - case BlockID.TRAP_DOOR: - case BlockID.WOODEN_DOOR: - case BlockID.FENCE_GATE: - case BlockID.ACACIA_FENCE_GATE: - case BlockID.BIRCH_FENCE_GATE: - case BlockID.DARK_OAK_FENCE_GATE: - case BlockID.JUNGLE_FENCE_GATE: - case BlockID.SPRUCE_FENCE_GATE: - case BlockID.LEVER: - case BlockID.WOODEN_BUTTON: - case BlockID.STONE_BUTTON: - case BlockID.STONE_PRESSURE_PLATE: - case BlockID.WOODEN_PRESSURE_PLATE: - case BlockID.PRESSURE_PLATE_HEAVY: - case BlockID.PRESSURE_PLATE_LIGHT: - case BlockID.POWERED_RAIL: - case BlockID.ACTIVATOR_RAIL: - case BlockID.DETECTOR_RAIL: - case BlockID.WATER: - case BlockID.STATIONARY_WATER: - case BlockID.LAVA: - case BlockID.STATIONARY_LAVA: - if (y == tmpLastY) { - return; + // For performance reasons, skip most checks + if ((++physSkip & 2047) != 0) return; + if (event.getChangedTypeId() == 0) return; + Exception e = new Exception(); + int depth = SharedSecrets.getJavaLangAccess().getStackTraceDepth(e); + if (depth >= Settings.IMP.TICK_LIMITER.PHYSICS) { + for (int frame = 25; frame < 33; frame++) { + StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame); + String methodName = elem.getMethodName(); + // setAir (hacky, but this needs to be efficient) + if (methodName.charAt(0) == 's' && methodName.length() == 6) { + Block block = event.getBlock(); + int cx = block.getX() >> 4; + int cz = block.getZ() >> 4; + if (rateLimit <= 0) { + rateLimit = 20; + Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled physics lag source at " + block.getLocation()); } - // Should cancel if excess, but need to be careful - amount = 1; - break; - case BlockID.SAND: - case BlockID.GRAVEL: - case BlockID.DRAGON_EGG: - case BlockID.ANVIL: - case BlockID.FIRE: - case BlockID.TORCH: - // If there's lots of this, it's usually from abuse - amount = 16; - break; - default: - // Uncategorized, but not redstone - amount = 4; - break; - } - if ((count[0] += amount) >= Settings.IMP.TICK_LIMITER.PHYSICS) { - cancelNearby(cx, cz); - if (rateLimit <= 0) { - rateLimit = 20; - Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled physics lag source at " + block.getLocation()); + cancelNearby(cx, cz); + event.setCancelled(true); + physCancel = true; + return; } - event.setCancelled(true); } } + physSkip = 1; + physCancel = false; } private void cancelNearby(int cx, int cz) { @@ -196,6 +158,7 @@ public class ChunkListener implements Listener { counter.put(key, badLimit); } + // Falling @EventHandler(priority = EventPriority.LOWEST) public void onBlockChange(EntityChangeBlockEvent event) { if (physicsFreeze) { @@ -214,13 +177,60 @@ public class ChunkListener implements Listener { } if (event.getEntityType() == EntityType.FALLING_BLOCK) { if (++count[1] >= Settings.IMP.TICK_LIMITER.FALLING) { - cancelNearby(cx, cz); - if (rateLimit <= 0) { - rateLimit = 20; - Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled falling block lag source at " + block.getLocation()); + + // Only cancel falling blocks when it's lagging + if (Fawe.get().getTimer().getTPS() < 18) { + cancelNearby(cx, cz); + if (rateLimit <= 0) { + rateLimit = 20; + Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled falling block lag source at " + block.getLocation()); + } + event.setCancelled(true); + return; + } else { + count[1] = 0; + } + } + } + } + + /** + * Prevent FireWorks from loading chunks + * @param event + */ + @EventHandler(priority = EventPriority.LOWEST) + public void onChunkLoad(ChunkLoadEvent event) { + Chunk chunk = event.getChunk(); + Entity[] entities = chunk.getEntities(); + World world = chunk.getWorld(); + + Exception e = new Exception(); + int start = 14; + int end = 22; + int depth = Math.min(end, SharedSecrets.getJavaLangAccess().getStackTraceDepth(e)); + + for (int frame = start; frame < depth; frame++) { + StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame); + String fileName = elem.getFileName(); + if (fileName.charAt(0) == 'E' && fileName.equals("EntityFireworks.java")) { + int chunkRange = 2; + for (int ocx = -chunkRange; ocx <= chunkRange; ocx++) { + for (int ocz = -chunkRange; ocz <= chunkRange; ocz++) { + int cx = chunk.getX() + ocx; + int cz = chunk.getZ() + ocz; + if (world.isChunkLoaded(cx, cz)) { + Chunk relativeChunk = world.getChunkAt(cx, cz); + Entity[] ents = relativeChunk.getEntities(); + for (Entity ent : ents) { + switch (ent.getType()) { + case FIREWORK: + Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled rogue FireWork at " + ent.getLocation()); + ent.remove(); + } + } + } + } } - event.setCancelled(true); - return; } } } diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index 9b2fe6e6..468f16c0 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -354,7 +354,7 @@ public class Settings extends Config { @Comment("Max falling blocks per interval (per chunk)") public int FALLING = 64; @Comment("Max physics per interval (per chunk)") - public int PHYSICS = 8192; + public int PHYSICS = 256; @Comment("Max item spawns per interval (per chunk)") public int ITEMS = 256; }