Fixes #870
This commit is contained in:
parent
274bc6d9a7
commit
9366acd6dc
@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.bukkit.chat.BukkitChatManager;
|
||||
import com.boydti.fawe.bukkit.listener.BrushListener;
|
||||
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
|
||||
import com.boydti.fawe.bukkit.listener.CFIPacketListener;
|
||||
import com.boydti.fawe.bukkit.listener.RenderListener;
|
||||
import com.boydti.fawe.bukkit.regions.FactionsFeature;
|
||||
@ -20,11 +21,11 @@ import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.boydti.fawe.bukkit.util.VaultUtil;
|
||||
import com.boydti.fawe.bukkit.util.cui.CUIListener;
|
||||
import com.boydti.fawe.bukkit.util.cui.StructureCUI;
|
||||
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener_8;
|
||||
import com.boydti.fawe.bukkit.v0.ChunkListener_9;
|
||||
import com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10;
|
||||
import com.boydti.fawe.bukkit.v1_11.BukkitQueue_1_11;
|
||||
import com.boydti.fawe.bukkit.v1_12.BukkitQueue_1_12;
|
||||
@ -147,7 +148,13 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
Bukkit.getPluginManager().registerEvents(FaweBukkit.this, FaweBukkit.this.plugin);
|
||||
|
||||
// The tick limiter
|
||||
new ChunkListener();
|
||||
try {
|
||||
Class.forName("sun.misc.SharedSecrets");
|
||||
new ChunkListener_8();
|
||||
} catch( ClassNotFoundException e )
|
||||
{
|
||||
new ChunkListener_9();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.v0;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
@ -21,12 +22,11 @@ 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 {
|
||||
public abstract class ChunkListener implements Listener {
|
||||
|
||||
private int rateLimit = 0;
|
||||
private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS, Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
|
||||
private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS, Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
|
||||
|
||||
public ChunkListener() {
|
||||
if (Settings.IMP.TICK_LIMITER.ENABLED) {
|
||||
@ -55,6 +55,9 @@ public class ChunkListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getDepth(Exception ex);
|
||||
protected abstract StackTraceElement getElement(Exception ex, int index);
|
||||
|
||||
public static boolean physicsFreeze = false;
|
||||
public static boolean itemFreeze = false;
|
||||
|
||||
@ -91,6 +94,9 @@ public class ChunkListener implements Listener {
|
||||
private boolean physCancel;
|
||||
private long physCancelPair;
|
||||
|
||||
private long physStart;
|
||||
private long physTick;
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPhysics(BlockPhysicsEvent event) {
|
||||
if (physCancel) {
|
||||
@ -105,25 +111,34 @@ public class ChunkListener implements Listener {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((++physSkip & 1023) != 0) return;
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
if (timer.getTick() != physTick) {
|
||||
physTick = timer.getTick();
|
||||
physStart = System.currentTimeMillis();
|
||||
return;
|
||||
} else if (System.currentTimeMillis() - physStart < Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
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) {
|
||||
int depth = getDepth(e);
|
||||
if (depth >= 256) {
|
||||
for (int frame = 25; frame < 33; frame++) {
|
||||
StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame);
|
||||
StackTraceElement elem = getElement(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;
|
||||
physCancelPair = MathMan.pairInt(cx, cz);
|
||||
if (rateLimit <= 0) {
|
||||
rateLimit = 20;
|
||||
Fawe.debug("[FAWE `tick-limiter`] Detected and cancelled physics lag source at " + block.getLocation());
|
||||
@ -145,12 +160,21 @@ public class ChunkListener implements Listener {
|
||||
cancel(cx - 1, cz);
|
||||
cancel(cx, cz + 1);
|
||||
cancel(cx, cz - 1);
|
||||
cancel(cx - 1, cz - 1);
|
||||
cancel(cx - 1, cz + 1);
|
||||
cancel(cx + 1, cz - 1);
|
||||
cancel(cx + 1, cz + 1);
|
||||
}
|
||||
|
||||
private void cancel(int cx, int cz) {
|
||||
long key = MathMan.pairInt(cx, cz);
|
||||
badChunks.put(key, (Boolean) true);
|
||||
counter.put(key, badLimit);
|
||||
int[] count = getCount(cx, cz);
|
||||
count[0] = Integer.MAX_VALUE;
|
||||
count[1] = Integer.MAX_VALUE;
|
||||
count[2] = Integer.MAX_VALUE;
|
||||
|
||||
}
|
||||
|
||||
// Falling
|
||||
@ -202,10 +226,10 @@ public class ChunkListener implements Listener {
|
||||
Exception e = new Exception();
|
||||
int start = 14;
|
||||
int end = 22;
|
||||
int depth = Math.min(end, SharedSecrets.getJavaLangAccess().getStackTraceDepth(e));
|
||||
int depth = Math.min(end, getDepth(e));
|
||||
|
||||
for (int frame = start; frame < depth; frame++) {
|
||||
StackTraceElement elem = SharedSecrets.getJavaLangAccess().getStackTraceElement(e, frame);
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
String className = elem.getClassName();
|
||||
int len = className.length();
|
||||
if (className != null) {
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import sun.misc.SharedSecrets;
|
||||
|
||||
public class ChunkListener_8 extends ChunkListener {
|
||||
|
||||
@Override
|
||||
protected int getDepth(Exception ex) {
|
||||
return SharedSecrets.getJavaLangAccess().getStackTraceDepth(ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StackTraceElement getElement(Exception ex, int index) {
|
||||
return SharedSecrets.getJavaLangAccess().getStackTraceElement(ex, index);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ChunkListener_9 extends ChunkListener {
|
||||
|
||||
private Method methodDepth;
|
||||
private Method methodGetStackTraceElement;
|
||||
private Exception exception;
|
||||
private StackTraceElement[] elements;
|
||||
|
||||
public ChunkListener_9() {
|
||||
if (Settings.IMP.TICK_LIMITER.ENABLED) {
|
||||
try {
|
||||
this.methodDepth = Throwable.class.getDeclaredMethod("getStackTraceDepth");
|
||||
this.methodDepth.setAccessible(true);
|
||||
this.methodGetStackTraceElement = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class);
|
||||
this.methodGetStackTraceElement.setAccessible(true);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StackTraceElement[] getElements(Exception ex) {
|
||||
if (elements == null || ex != exception) {
|
||||
exception = ex;
|
||||
elements = ex.getStackTrace();
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDepth(Exception ex) {
|
||||
if (methodDepth != null) {
|
||||
try {
|
||||
return (int) methodDepth.invoke(ex);
|
||||
} catch (Throwable t) {
|
||||
methodDepth = null;
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return getElements(ex).length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StackTraceElement getElement(Exception ex, int i) {
|
||||
if (methodGetStackTraceElement != null) {
|
||||
try {
|
||||
return (StackTraceElement) methodGetStackTraceElement.invoke(ex, i);
|
||||
} catch (Throwable t) {
|
||||
methodGetStackTraceElement = null;
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return getElements(ex)[i];
|
||||
}
|
||||
}
|
@ -353,8 +353,8 @@ public class Settings extends Config {
|
||||
public int INTERVAL = 20;
|
||||
@Comment("Max falling blocks per interval (per chunk)")
|
||||
public int FALLING = 64;
|
||||
@Comment("Max physics per interval (per chunk)")
|
||||
public int PHYSICS = 256;
|
||||
@Comment("Max physics per interval (excluding redstone)")
|
||||
public int PHYSICS_MS = 50;
|
||||
@Comment("Max item spawns per interval (per chunk)")
|
||||
public int ITEMS = 256;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user