diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java index 000d6782..5740a2fe 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/BukkitPlayer.java @@ -36,12 +36,16 @@ public class BukkitPlayer extends FawePlayer { * Permissions are used to managing WorldEdit region restrictions * - The `/wea` command will give/remove the required bypass permission */ - if (Fawe. imp().getVault() == null) { + if (Fawe. imp().getVault() == null || Fawe. imp().getVault().permission == null) { this.parent.addAttachment(Fawe. imp()).setPermission("fawe.bypass", flag); } else if (flag) { - Fawe. imp().getVault().permission.playerAdd(this.parent, perm); + if (!Fawe. imp().getVault().permission.playerAdd(this.parent, perm)) { + this.parent.addAttachment(Fawe. imp()).setPermission("fawe.bypass", flag); + } } else { - Fawe. imp().getVault().permission.playerRemove(this.parent, perm); + if (!Fawe. imp().getVault().permission.playerRemove(this.parent, perm)) { + this.parent.addAttachment(Fawe. imp()).setPermission("fawe.bypass", flag); + } } } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index ee8eba0b..c450a0d9 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -24,7 +24,6 @@ import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import java.io.File; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -59,13 +58,6 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener { try { Bukkit.getPluginManager().registerEvents(this, this); Fawe.set(this); - try { - final Class clazz = Class.forName("org.spigotmc.AsyncCatcher"); - final Field field = clazz.getDeclaredField("enabled"); - field.set(null, false); - } catch (final Throwable e) { - e.printStackTrace(); - } } catch (final Throwable e) { e.printStackTrace(); this.getServer().shutdown(); diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java index 56a238cb..e924a9da 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitQueue_1_8.java @@ -74,7 +74,7 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 { private RefMethod methodGetWorld; private RefField tileEntityListTick; - public BukkitQueue_1_8(String world) { + public BukkitQueue_1_8(final String world) { super(world); try { this.methodGetHandlePlayer = this.classCraftPlayer.getMethod("getHandle"); @@ -95,6 +95,69 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 { } catch (final NoSuchMethodException e) { e.printStackTrace(); } + TaskManager.IMP.repeat(new Runnable() { + @Override + public void run() { + synchronized (loadQueue) { + while (loadQueue.size() > 0) { + IntegerPair loc = loadQueue.poll(); + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + if (!bukkitWorld.isChunkLoaded(loc.x, loc.z)) { + bukkitWorld.loadChunk(loc.x, loc.z); + } + } + loadQueue.notifyAll(); + } + } + }, 1); + } + + private ArrayDeque loadQueue = new ArrayDeque<>(); + + @Override + public int getCombinedId4Data(int x, int y, int z) { + if (y < 0 || y > 255) { + return 0; + } + int cx = x >> 4; + int cz = z >> 4; + int cy = y >> 4; + if (cx != lcx || cz != lcz) { + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + lcx = cx; + lcz = cz; + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + if (Settings.CHUNK_WAIT > 0) { + synchronized (loadQueue) { + loadQueue.add(new IntegerPair(cx, cz)); + try { + loadQueue.wait(Settings.CHUNK_WAIT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + return 0; + } + } else { + return 0; + } + } + lc = methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call(); + } else if (cy == lcy) { + return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0; + } + Object storage = ((Object[]) fieldSections.of(lc).get())[cy]; + if (storage == null) { + ls = null; + return 0; + } + ls = getIdArray(storage); + return ls[FaweCache.CACHE_J[y][x & 15][z & 15]]; } @Override @@ -255,36 +318,6 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 { private char[] ls; private World bukkitWorld; - @Override - public int getCombinedId4Data(int x, int y, int z) { - if (y < 0 || y > 255) { - return 0; - } - int cx = x >> 4; - int cz = z >> 4; - int cy = y >> 4; - if (cx != lcx || cz != lcz) { - if (bukkitWorld == null) { - bukkitWorld = Bukkit.getServer().getWorld(world); - } - lcx = cx; - lcz = cz; - if (!bukkitWorld.isChunkLoaded(cx, cz)) { - return 0; - } - lc = methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call(); - } else if (cy == lcy) { - return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0; - } - Object storage = ((Object[]) fieldSections.of(lc).get())[cy]; - if (storage == null) { - ls = null; - return 0; - } - ls = getIdArray(storage); - return ls[FaweCache.CACHE_J[y][x & 15][z & 15]]; - } - @Override public boolean setComponents(final FaweChunk fc) { try { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java index d8c1e962..5ca2211e 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java @@ -70,7 +70,7 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 { private final RefMethod methodGetWorld; private final RefField tileEntityListTick; - public BukkitQueue_1_9(String world) throws NoSuchMethodException, RuntimeException { + public BukkitQueue_1_9(final String world) throws NoSuchMethodException, RuntimeException { super(world); this.methodGetHandleChunk = this.classCraftChunk.getMethod("getHandle"); this.methodInitLighting = this.classChunk.getMethod("initLighting"); @@ -87,6 +87,71 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 { this.tileEntityListTick = this.classWorld.getField("tileEntityListTick"); this.methodGetWorld = this.classChunk.getMethod("getWorld"); this.methodGetCombinedId = classBlock.getMethod("getCombinedId", classIBlockData.getRealClass()); + TaskManager.IMP.repeat(new Runnable() { + @Override + public void run() { + synchronized (loadQueue) { + if (loadQueue.size() > 0) { + Fawe.debug("Loading " + loadQueue.size() + " chunks."); + } + while (loadQueue.size() > 0) { + IntegerPair loc = loadQueue.poll(); + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + if (!bukkitWorld.isChunkLoaded(loc.x, loc.z)) { + bukkitWorld.loadChunk(loc.x, loc.z); + } + } + loadQueue.notifyAll(); + } + } + }, 1); + } + + private ArrayDeque loadQueue = new ArrayDeque<>(); + + @Override + public int getCombinedId4Data(int x, int y, int z) { + if (y < 0 || y > 255) { + return 0; + } + try { + int cx = x >> 4; + int cz = z >> 4; + int cy = y >> 4; + if (cx != lcx || cz != lcz) { + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + lcx = cx; + lcz = cz; + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + if (Settings.CHUNK_WAIT > 0) { + synchronized (loadQueue) { + loadQueue.add(new IntegerPair(cx, cz)); + try { + loadQueue.wait(Settings.CHUNK_WAIT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + return 0; + } + } else { + return 0; + } + } + lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call()); + } + int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15)); + return ((combined & 4095) << 4) + (combined >> 12); + } + catch (Throwable e) { + e.printStackTrace(); + } + return 0; } @Override @@ -230,35 +295,6 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 { private RefExecutor lc; private World bukkitWorld; - @Override - public int getCombinedId4Data(int x, int y, int z) { - if (y < 0 || y > 255) { - return 0; - } - try { - int cx = x >> 4; - int cz = z >> 4; - int cy = y >> 4; - if (cx != lcx || cz != lcz) { - if (bukkitWorld == null) { - bukkitWorld = Bukkit.getServer().getWorld(world); - } - lcx = cx; - lcz = cz; - if (!bukkitWorld.isChunkLoaded(cx, cz)) { - return 0; - } - lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call()); - } - int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15)); - return ((combined & 4095) << 4) + (combined >> 12); - } - catch (Throwable e) { - e.printStackTrace(); - } - return 0; - } - @Override public boolean setComponents(final FaweChunk pc) { final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc; 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 8d2019a4..8f9aac62 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -24,6 +24,8 @@ public class Settings { public static int COMPRESSION_LEVEL = 0; public static int BUFFER_SIZE = 531441; public static boolean METRICS = true; + public static int CHUNK_WAIT = 0; + public static boolean REGION_RESTRICTIONS = true; public static HashMap limits; @@ -66,6 +68,9 @@ public class Settings { options.put("fix-all-lighting", FIX_ALL_LIGHTING); options.put("history.use-disk", STORE_HISTORY_ON_DISK); options.put("history.compress", false); + options.put("history.chunk-wait-ms", CHUNK_WAIT); + options.put("history.buffer-size", BUFFER_SIZE); + options.put("region-restrictions", REGION_RESTRICTIONS); options.put("metrics", METRICS); // Default limit @@ -91,9 +96,11 @@ public class Settings { REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask"); WE_BLACKLIST = config.getStringList("command-blacklist"); ENABLE_HARD_LIMIT = config.getBoolean("crash-mitigation"); + REGION_RESTRICTIONS = config.getBoolean("region-restrictions"); METRICS = config.getBoolean("metrics"); COMPRESSION_LEVEL = config.getInt("history.compression-level", config.getBoolean("history.compress") ? 1 : 0); - BUFFER_SIZE = config.getInt("history.buffer-size", 59049); + BUFFER_SIZE = config.getInt("history.buffer-size", BUFFER_SIZE); + CHUNK_WAIT = config.getInt("history.chunk-wait-ms"); if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) { LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; } diff --git a/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java b/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java index c0a865d6..dc0ba86c 100644 --- a/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/HistoryExtent.java @@ -69,7 +69,11 @@ public class HistoryExtent extends AbstractDelegateExtent { this.changeSet.add(x, y, z, combined, (block.getId() << 4) + block.getData()); } } else { - this.changeSet.add(location, getBlock(location), block); + try { + this.changeSet.add(location, getBlock(location), block); + } catch (Throwable e) { + this.changeSet.add(x, y, z, combined, block); + } } return true; } diff --git a/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java index c9e3f813..e4025b7a 100644 --- a/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java +++ b/core/src/main/java/com/boydti/fawe/regions/general/PlotSquaredFeature.java @@ -28,7 +28,10 @@ public class PlotSquaredFeature extends FaweMaskManager { int min = Integer.MAX_VALUE; for (final Plot p : pp.getPlots()) { if (p.getArea().worldname.equals(world)) { - final double d = p.getHome().getEuclideanDistanceSquared(loc); + Location bot = p.getBottomAbs(); + Location top = p.getTopAbs(); + Location center = new Location(bot.getWorld(), (bot.getX() + top.getX())/2, 0, (bot.getZ() + top.getZ()) / 2); + final double d = center.getEuclideanDistanceSquared(loc); if (d < min) { min = (int) d; plot = p; diff --git a/core/src/main/java/com/boydti/fawe/util/WEManager.java b/core/src/main/java/com/boydti/fawe/util/WEManager.java index c0717991..23811d86 100644 --- a/core/src/main/java/com/boydti/fawe/util/WEManager.java +++ b/core/src/main/java/com/boydti/fawe/util/WEManager.java @@ -1,6 +1,7 @@ package com.boydti.fawe.util; import com.boydti.fawe.config.BBC; +import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.extent.NullExtent; @@ -39,7 +40,7 @@ public class WEManager { public HashSet getMask(final FawePlayer player) { final HashSet regions = new HashSet<>(); - if (player.hasPermission("fawe.bypass")) { + if (player.hasPermission("fawe.bypass") || !Settings.REGION_RESTRICTIONS) { regions.add(new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE)); return regions; } diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 15123031..2382d22a 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -549,7 +549,11 @@ public class EditSession implements Extent { if (!FaweCache.hasNBT(combinedId4Data >> 4)) { return FaweCache.CACHE_BLOCK[combinedId4Data]; } - return this.world.getLazyBlock(position); + try { + return this.world.getLazyBlock(position); + } catch (Throwable e) { + return FaweCache.CACHE_BLOCK[combinedId4Data]; + } } @Override diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 0c248399..cd54321e 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -237,7 +237,7 @@ public final class CommandManager { locals.put(Actor.class, actor); locals.put("arguments", event.getArguments()); - long start = System.currentTimeMillis(); + final long start = System.currentTimeMillis(); FawePlayer fp; if (actor.isPlayer()) { fp = Fawe.imp().wrap(actor.getName()); @@ -292,6 +292,7 @@ public final class CommandManager { SetQueue.IMP.addTask(new Runnable() { @Override public void run() { + final long time = System.currentTimeMillis() - start; actor.print(BBC.PREFIX.s() + " Action completed in " + (time / 1000d) + " seconds"); } }); diff --git a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java index d9898a07..ce9b146c 100644 --- a/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java +++ b/core/src/main/java/com/sk89q/worldedit/function/visitor/RegionVisitor.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.function.visitor; -import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.regions.Region; -import java.util.Iterator; import java.util.List; /** @@ -34,15 +33,13 @@ import java.util.List; */ public class RegionVisitor implements Operation { + private final Region region; private final RegionFunction function; private int affected = 0; - private final Iterator iterator; - - public RegionVisitor(final Region region, final RegionFunction function) { + public RegionVisitor(Region region, RegionFunction function) { + this.region = region; this.function = function; - this.iterator = region.iterator(); - } /** @@ -56,11 +53,12 @@ public class RegionVisitor implements Operation { @Override public Operation resume(final RunContext run) throws WorldEditException { - while (this.iterator.hasNext()) { - if (this.function.apply(this.iterator.next())) { + for (Vector pt : region) { + if (function.apply(pt)) { affected++; } } + return null; } diff --git a/forge/src/main/java/com/boydti/fawe/forge/v1_8/SpongeQueue_1_8.java b/forge/src/main/java/com/boydti/fawe/forge/v1_8/SpongeQueue_1_8.java index 11217b53..cf42bd33 100644 --- a/forge/src/main/java/com/boydti/fawe/forge/v1_8/SpongeQueue_1_8.java +++ b/forge/src/main/java/com/boydti/fawe/forge/v1_8/SpongeQueue_1_8.java @@ -5,9 +5,11 @@ import com.boydti.fawe.config.Settings; import com.boydti.fawe.forge.SpongeUtil; import com.boydti.fawe.forge.v0.SpongeQueue_0; import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.IntegerPair; import com.boydti.fawe.object.PseudoRandom; import com.boydti.fawe.util.TaskManager; import com.flowpowered.math.vector.Vector3i; +import java.util.ArrayDeque; import java.util.Collection; import java.util.Iterator; import java.util.Map; @@ -34,6 +36,69 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 { public SpongeQueue_1_8(String world) { super(world); + TaskManager.IMP.repeat(() -> { + synchronized (loadQueue) { + while (loadQueue.size() > 0) { + IntegerPair loc = loadQueue.poll(); + if (spongeWorld == null) { + spongeWorld = Sponge.getServer().getWorld(world).get(); + } + Chunk chunk = spongeWorld.getChunk(loc.x, 0, loc.z).orElse(null); + if (chunk == null || !chunk.isLoaded()) { + spongeWorld.loadChunk(loc.x, 0, loc.z, true); + } + } + loadQueue.notifyAll(); + } + }, 1); + } + + private ArrayDeque loadQueue = new ArrayDeque<>(); + + @Override + public int getCombinedId4Data(int x, int y, int z) { + if (y < 0 || y > 255) { + return 0; + } + int cx = x >> 4; + int cz = z >> 4; + int cy = y >> 4; + if (cx != lcx || cz != lcz) { + if (spongeWorld == null) { + spongeWorld = Sponge.getServer().getWorld(world).get(); + } + lcx = cx; + lcz = cz; + Chunk chunk = spongeWorld.getChunk(cx, 0, cz).orElse(null); + if (chunk == null || !chunk.isLoaded()) { + if (Settings.CHUNK_WAIT > 0) { + synchronized (loadQueue) { + loadQueue.add(new IntegerPair(cx, cz)); + try { + loadQueue.wait(Settings.CHUNK_WAIT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + chunk = spongeWorld.getChunk(cx, 0, cz).orElse(null); + if (chunk == null || !chunk.isLoaded()) { + return 0; + } + } else { + return 0; + } + } + lc = (net.minecraft.world.chunk.Chunk) chunk; + } else if (cy == lcy) { + return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0; + } + ExtendedBlockStorage storage = lc.getBlockStorageArray()[cy]; + if (storage == null) { + ls = null; + return 0; + } + ls = storage.getData(); + return ls[FaweCache.CACHE_J[y][x & 15][z & 15]]; } @Override @@ -86,33 +151,6 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 { private net.minecraft.world.chunk.Chunk lc; private char[] ls; - @Override - public int getCombinedId4Data(int x, int y, int z) { - if (y < 0 || y > 255) { - return 0; - } - int cx = x >> 4; - int cz = z >> 4; - int cy = y >> 4; - if (cx != lcx || cz != lcz) { - if (spongeWorld == null) { - spongeWorld = Sponge.getServer().getWorld(world).get(); - } - lcx = cx; - lcz = cz; - lc = (net.minecraft.world.chunk.Chunk) spongeWorld.getChunk(cx, 0, cz).get(); - } else if (cy == lcy) { - return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0; - } - ExtendedBlockStorage storage = lc.getBlockStorageArray()[cy]; - if (storage == null) { - ls = null; - return 0; - } - ls = storage.getData(); - return ls[FaweCache.CACHE_J[y][x & 15][z & 15]]; - } - @Override public boolean setComponents(FaweChunk fc) { SpongeChunk_1_8 fs = (SpongeChunk_1_8) fc;