mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2025-01-01 14:08:11 +01:00
parent
9366acd6dc
commit
4b7c1e987b
@ -25,7 +25,7 @@ import org.bukkit.event.world.ChunkLoadEvent;
|
||||
|
||||
public abstract class ChunkListener implements Listener {
|
||||
|
||||
private int rateLimit = 0;
|
||||
protected int rateLimit = 0;
|
||||
private int[] badLimit = new int[]{Settings.IMP.TICK_LIMITER.PHYSICS_MS, Settings.IMP.TICK_LIMITER.FALLING, Settings.IMP.TICK_LIMITER.ITEMS};
|
||||
|
||||
public ChunkListener() {
|
||||
@ -61,7 +61,7 @@ public abstract class ChunkListener implements Listener {
|
||||
public static boolean physicsFreeze = false;
|
||||
public static boolean itemFreeze = false;
|
||||
|
||||
private Long2ObjectOpenHashMap<Boolean> badChunks = new Long2ObjectOpenHashMap<>();
|
||||
protected Long2ObjectOpenHashMap<Boolean> badChunks = new Long2ObjectOpenHashMap<>();
|
||||
private Long2ObjectOpenHashMap<int[]> counter = new Long2ObjectOpenHashMap<>();
|
||||
private int lastX = Integer.MIN_VALUE, lastZ = Integer.MIN_VALUE;
|
||||
private int[] lastCount;
|
||||
@ -90,12 +90,13 @@ public abstract class ChunkListener implements Listener {
|
||||
|
||||
}
|
||||
|
||||
private int physSkip;
|
||||
private boolean physCancel;
|
||||
private long physCancelPair;
|
||||
protected int physSkip;
|
||||
protected boolean physCancel;
|
||||
protected long physCancelPair;
|
||||
|
||||
protected long physStart;
|
||||
protected long physTick;
|
||||
|
||||
private long physStart;
|
||||
private long physTick;
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPhysics(BlockPhysicsEvent event) {
|
||||
@ -130,31 +131,40 @@ public abstract class ChunkListener implements Listener {
|
||||
Exception e = new Exception();
|
||||
int depth = getDepth(e);
|
||||
if (depth >= 256) {
|
||||
for (int frame = 25; frame < 33; 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 (containsSetAir(e, event)) {
|
||||
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());
|
||||
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;
|
||||
}
|
||||
cancelNearby(cx, cz);
|
||||
event.setCancelled(true);
|
||||
physCancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
physSkip = 1;
|
||||
physCancel = false;
|
||||
}
|
||||
|
||||
private void cancelNearby(int cx, int cz) {
|
||||
protected boolean containsSetAir(Exception e, BlockPhysicsEvent event) {
|
||||
for (int frame = 25; frame < 33; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
if (elem != null) {
|
||||
String methodName = elem.getMethodName();
|
||||
// setAir (hacky, but this needs to be efficient)
|
||||
if (methodName.charAt(0) == 's' && methodName.length() == 6) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void cancelNearby(int cx, int cz) {
|
||||
cancel(cx, cz);
|
||||
cancel(cx + 1, cz);
|
||||
cancel(cx - 1, cz);
|
||||
@ -219,34 +229,37 @@ public abstract class ChunkListener implements Listener {
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
Chunk chunk = event.getChunk();
|
||||
Entity[] entities = chunk.getEntities();
|
||||
World world = chunk.getWorld();
|
||||
if (!Settings.IMP.TICK_LIMITER.FIREWORKS_LOAD_CHUNKS) {
|
||||
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, getDepth(e));
|
||||
Exception e = new Exception();
|
||||
int start = 14;
|
||||
int end = 22;
|
||||
int depth = Math.min(end, getDepth(e));
|
||||
|
||||
for (int frame = start; frame < depth; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
String className = elem.getClassName();
|
||||
int len = className.length();
|
||||
if (className != null) {
|
||||
if (className.charAt(len - 15) == 'E' && className.endsWith("EntityFireworks")) {
|
||||
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();
|
||||
for (int frame = start; frame < depth; frame++) {
|
||||
StackTraceElement elem = getElement(e, frame);
|
||||
if (elem == null) return;
|
||||
String className = elem.getClassName();
|
||||
int len = className.length();
|
||||
if (className != null) {
|
||||
if (len > 15 && className.charAt(len - 15) == 'E' && className.endsWith("EntityFireworks")) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,159 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import java.lang.reflect.Method;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockBurnEvent;
|
||||
import org.bukkit.event.block.BlockCanBuildEvent;
|
||||
import org.bukkit.event.block.BlockDamageEvent;
|
||||
import org.bukkit.event.block.BlockDispenseEvent;
|
||||
import org.bukkit.event.block.BlockExpEvent;
|
||||
import org.bukkit.event.block.BlockExplodeEvent;
|
||||
import org.bukkit.event.block.BlockFadeEvent;
|
||||
import org.bukkit.event.block.BlockFromToEvent;
|
||||
import org.bukkit.event.block.BlockGrowEvent;
|
||||
import org.bukkit.event.block.BlockIgniteEvent;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
import org.bukkit.event.block.BlockPistonEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.event.block.CauldronLevelChangeEvent;
|
||||
import org.bukkit.event.block.LeavesDecayEvent;
|
||||
import org.bukkit.event.block.NotePlayEvent;
|
||||
import org.bukkit.event.block.SignChangeEvent;
|
||||
import org.bukkit.event.inventory.BrewEvent;
|
||||
import org.bukkit.event.inventory.BrewingStandFuelEvent;
|
||||
import org.bukkit.event.inventory.FurnaceBurnEvent;
|
||||
import org.bukkit.event.inventory.FurnaceSmeltEvent;
|
||||
|
||||
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);
|
||||
super();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
physSkip = 0;
|
||||
physStart = System.currentTimeMillis();
|
||||
physCancel = false;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockBurnEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockCanBuildEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockDamageEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockDispenseEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockExpEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockExplodeEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockFadeEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockFromToEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockGrowEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockIgniteEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event( BlockPistonEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockPlaceEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BrewEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BrewingStandFuelEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(CauldronLevelChangeEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(FurnaceBurnEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(FurnaceSmeltEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(LeavesDecayEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(NotePlayEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(SignChangeEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void event(BlockRedstoneEvent event) { reset(); }
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPhysics(BlockPhysicsEvent event) {
|
||||
if (physicsFreeze) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
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 (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
physCancelPair = pair;
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
if (timer.getTick() != physTick) {
|
||||
physTick = timer.getTick();
|
||||
physStart = System.currentTimeMillis();
|
||||
physSkip = 0;
|
||||
physCancel = false;
|
||||
return;
|
||||
}
|
||||
if ((++physSkip & 1023) == 0) {
|
||||
if (System.currentTimeMillis() - physStart > Settings.IMP.TICK_LIMITER.PHYSICS_MS) {
|
||||
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());
|
||||
}
|
||||
cancelNearby(cx, cz);
|
||||
event.setCancelled(true);
|
||||
physCancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -33,27 +168,12 @@ public class ChunkListener_9 extends ChunkListener {
|
||||
|
||||
@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];
|
||||
StackTraceElement[] elems = getElements(ex);
|
||||
return elems.length > i ? elems[i] : null;
|
||||
}
|
||||
}
|
@ -357,6 +357,12 @@ public class Settings extends Config {
|
||||
public int PHYSICS_MS = 50;
|
||||
@Comment("Max item spawns per interval (per chunk)")
|
||||
public int ITEMS = 256;
|
||||
@Comment({
|
||||
"Whether fireworks can load chunks",
|
||||
" - Fireworks usually travel vertically so do not load any chunks",
|
||||
" - Horizontal fireworks can be hacked in to crash a server"
|
||||
})
|
||||
public boolean FIREWORKS_LOAD_CHUNKS = false;
|
||||
}
|
||||
|
||||
public static class CLIPBOARD {
|
||||
|
@ -794,7 +794,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
||||
|
||||
@Override
|
||||
public void setChunk(FaweChunk chunk) {
|
||||
System.out.println(((SimpleCharFaweChunk) chunk).getTotalCount());
|
||||
char[][] src = chunk.getCombinedIdArrays();
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
if (src[i] != null) {
|
||||
|
Loading…
Reference in New Issue
Block a user