This commit is contained in:
Jesse Boyd 2018-01-07 21:25:49 +11:00
parent 189e8189fb
commit e1e31beff0
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
2 changed files with 106 additions and 96 deletions

View File

@ -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;
}
}
}

View File

@ -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;
}