Fixes #847
This commit is contained in:
parent
189e8189fb
commit
e1e31beff0
@ -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.<FaweBukkit>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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user