diff --git a/build.gradle b/build.gradle index bb23fb11..000d852b 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } group = 'com.boydti.fawe' -version = '3.4.1' +version = '3.4.2' description = """FastAsyncWorldEdit""" subprojects { diff --git a/bukkit/build/resources/main/plugin.yml b/bukkit/build/resources/main/plugin.yml index 19310c70..e35720e6 100644 --- a/bukkit/build/resources/main/plugin.yml +++ b/bukkit/build/resources/main/plugin.yml @@ -1,6 +1,6 @@ name: FastAsyncWorldEdit main: com.boydti.fawe.bukkit.FaweBukkit -version: 3.4.1 +version: 3.4.2 description: Fast Async WorldEdit plugin authors: [Empire92] loadbefore: [WorldEdit] diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java index b52d8d75..4b067b9e 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_All.java @@ -13,6 +13,8 @@ import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.bukkit.BukkitUtil; import com.sk89q.worldedit.world.biome.BaseBiome; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import org.bukkit.Bukkit; @@ -56,6 +58,35 @@ public class BukkitQueue_All extends BukkitQueue_0 { } } + private volatile boolean timingsEnabled; + + @Override + public void startSet(boolean parallel) { + if (parallel) { + try { + Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled"); + fieldEnabled.setAccessible(true); + timingsEnabled = (boolean) fieldEnabled.get(null); + if (timingsEnabled) { + fieldEnabled.set(null, false); + Method methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled"); + methodCheck.setAccessible(true); + methodCheck.invoke(null); + } + } catch (Throwable ignore) {} + try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {} + } + } + + @Override + public void endSet(boolean parallel) { + if (parallel) { + try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled); + } catch (Throwable ignore) {ignore.printStackTrace();} + try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {} + } + } + @Override public Collection> sendChunk(Collection> fcs) { return new ArrayList<>(); 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 341a1f23..f17ae3e2 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 @@ -129,7 +129,7 @@ public class BukkitQueue_1_8 extends BukkitQueue_All { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) { 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 94b00257..22ead84c 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 @@ -115,7 +115,7 @@ public class BukkitQueue_1_9 extends BukkitQueue_All { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java index 9d78b440..1988b3c8 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -45,8 +45,6 @@ import org.bukkit.generator.ChunkGenerator; public class BukkitQueue_1_9_R1 extends BukkitQueue_All { - private IBlockData air = Block.getByCombinedId(0); - public BukkitQueue_1_9_R1(final String world) throws NoSuchMethodException, RuntimeException { super(world); } @@ -87,7 +85,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) { @@ -304,7 +302,6 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All { continue; } DataPaletteBlock nibble = section.getBlocks(); - Field fieldBits = nibble.getClass().getDeclaredField("b"); fieldBits.setAccessible(true); DataBits bits = (DataBits) fieldBits.get(nibble); @@ -424,12 +421,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All { } } } - TaskManager.IMP.later(new Runnable() { - @Override - public void run() { - sendChunk(fs); - } - }, 1); + sendChunk(fs); return true; } diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index 19310c70..e35720e6 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: FastAsyncWorldEdit main: com.boydti.fawe.bukkit.FaweBukkit -version: 3.4.1 +version: 3.4.2 description: Fast Async WorldEdit plugin authors: [Empire92] loadbefore: [WorldEdit] diff --git a/core/src/main/java/com/boydti/fawe/command/Cancel.java b/core/src/main/java/com/boydti/fawe/command/Cancel.java index e845add6..848b6cb4 100644 --- a/core/src/main/java/com/boydti/fawe/command/Cancel.java +++ b/core/src/main/java/com/boydti/fawe/command/Cancel.java @@ -51,6 +51,7 @@ public class Cancel extends FaweCommand { session.bypassReorderHistory = nullExtent; session.faweExtent = nullExtent; queue.clear(); + SetQueue.IMP.dequeue(queue); } } } diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java index ca0dfe95..db25ec50 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/DiskOptimizedClipboard.java @@ -5,8 +5,10 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.BufferedRandomAccessFile; import com.boydti.fawe.object.IntegerTrio; +import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; @@ -173,10 +175,11 @@ public class DiskOptimizedClipboard extends FaweClipboard { if (raf != null) { close(); } + lastAccessed = System.currentTimeMillis(); this.raf = new BufferedRandomAccessFile(file, "rw", Settings.BUFFER_SIZE); - long size = width * height * length * 2l; + long size = width * height * length * 2l + HEADER_SIZE; if (raf.length() != size) { - raf.setLength(size + HEADER_SIZE); + raf.setLength(size); // write length etc raf.seek(0); last = 0; @@ -208,6 +211,54 @@ public class DiskOptimizedClipboard extends FaweClipboard { private int zlast; private int zlasti; + @Override + public void forEach(final RunnableVal2 task, boolean air) { + try { + if (raf == null) { + open(); + } + raf.seek(HEADER_SIZE); + BlockVector pos = new BlockVector(0, 0, 0); + int x = 0; + int y = 0; + int z = 0; + long len = (raf.length()); + for (long i = HEADER_SIZE; i < len; i+=2) { + pos.x = x; + pos.y = y; + pos.z = z; + if (++x >= width) { + x = 0; + if (++z >= length) { + z = 0; + ++y; + } + } + raf.seek(i); + raf.read(buffer); + int id = ((((int) buffer[1] & 0xFF) << 4) + (((int) buffer[0] & 0xFF) >> 4)); + if (id == 0 && !air) { + continue; + } + BaseBlock block; + if (!FaweCache.hasData(id)) { + block = FaweCache.CACHE_BLOCK[id << 4]; + } else { + block = FaweCache.CACHE_BLOCK[(id << 4) + (buffer[0] & 0xF)]; + } + if (FaweCache.hasNBT(id)) { + CompoundTag nbt = nbtMap.get(new IntegerTrio((int) pos.x, (int) pos.y, (int) pos.z)); + if (nbt != null) { + block = new BaseBlock(block.getId(), block.getData()); + block.setNbtData(nbt); + } + } + task.run(pos, block); + } + } catch (IOException e) { + e.printStackTrace(); + } + } @Override public BaseBlock getBlock(int x, int y, int z) { @@ -218,6 +269,7 @@ public class DiskOptimizedClipboard extends FaweClipboard { int i = x + ((ylast == y) ? ylasti : (ylasti = ((ylast = y)) * area)) + ((zlast == z) ? zlasti : (zlasti = (zlast = z) * width)); if (i != last + 1) { raf.seek((HEADER_SIZE) + (i << 1)); + lastAccessed = System.currentTimeMillis(); } raf.read(buffer); last = i; @@ -248,10 +300,10 @@ public class DiskOptimizedClipboard extends FaweClipboard { if (raf == null) { open(); } - lastAccessed = System.currentTimeMillis(); int i = x + ((ylast == y) ? ylasti : (ylasti = ((ylast = y)) * area)) + ((zlast == z) ? zlasti : (zlasti = (zlast = z) * width)); if (i != last + 1) { raf.seek((HEADER_SIZE) + (i << 1)); + lastAccessed = System.currentTimeMillis(); } last = i; final int id = block.getId(); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java index 959889e5..785a2b32 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/FaweClipboard.java @@ -1,5 +1,6 @@ package com.boydti.fawe.object.clipboard; +import com.boydti.fawe.object.RunnableVal2; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; @@ -25,6 +26,8 @@ public abstract class FaweClipboard { public void setOrigin(Vector offset) {} // Do nothing + public abstract void forEach(final RunnableVal2 task, boolean air); + /** * Stores entity data. */ diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboard.java index 49a22b06..000d1e47 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/LazyClipboard.java @@ -8,6 +8,26 @@ import java.util.List; public abstract class LazyClipboard extends FaweClipboard { +// private final int width, height, length; +// +// public LazyClipboard(int width, int height, int length) { +// this.width = width; +// this.height = height; +// this.length = length; +// } +// +// @Override +// public void forEach(RunnableVal2 task, boolean air) { +// BlockVector pos = new BlockVector(0, 0, 0); +// for (pos.x = 0; pos.x < width; pos.x++) { +// for (pos.z = 0; pos.z < width; pos.z++) { +// for (pos.y = 0; pos.y < width; pos.y++) { +// task.run(pos, getBlock((int) pos.x, (int) pos.y, (int) pos.z)); +// } +// } +// } +// } + @Override public abstract BaseBlock getBlock(int x, int y, int z); diff --git a/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java b/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java index ab8845f9..e7ddf321 100644 --- a/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java +++ b/core/src/main/java/com/boydti/fawe/object/clipboard/MemoryOptimizedClipboard.java @@ -2,7 +2,11 @@ package com.boydti.fawe.object.clipboard; import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.IntegerTrio; +import com.boydti.fawe.object.RunnableVal2; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -69,6 +73,63 @@ public class MemoryOptimizedClipboard extends FaweClipboard { return block; } + @Override + public void forEach(final RunnableVal2 task, boolean air) { + BlockVector pos = new BlockVector(0, 0, 0); + int y1max = ((height + 15) >> 4); + for (int x = 0; x < width; x++) { + int i1 = x; + for (int z = 0; z < length; z++) { + int i2 = i1 + z * width; + for (int y = 0; y < y1max; y++) { + int y1 = y << 4; + int i = i2 + y * area; + byte[] idArray = ids[i]; + if (idArray == null) { + if (!air) { + continue; + } + for (int y2 = 0; y2 < 16; y2++) { + pos.x = x; + pos.z = z; + pos.y = y1 + y2; + task.run(pos, EditSession.nullBlock); + } + continue; + } + for (int y2 = 0; y2 < idArray.length; y2++) { + int id = idArray[y2] & 0xFF; + if (id == 0 && !air) { + continue; + } + pos.x = x; + pos.z = z; + pos.y = y1 + y2; + BaseBlock block; + if (!FaweCache.hasData(id) || datas == null) { + block = FaweCache.CACHE_BLOCK[id << 4]; + } else { + byte[] dataArray = datas[i]; + if (dataArray == null) { + block = FaweCache.CACHE_BLOCK[id << 4]; + } else { + block = FaweCache.CACHE_BLOCK[(id << 4) + dataArray[y2]]; + } + } + if (FaweCache.hasNBT(id)) { + CompoundTag nbt = nbtMap.get(new IntegerTrio((int) pos.x, (int) pos.y, (int) pos.z)); + if (nbt != null) { + block = new BaseBlock(block.getId(), block.getData()); + block.setNbtData(nbt); + } + } + task.run(pos, block); + } + } + } + } + } + @Override public boolean setBlock(int x, int y, int z, BaseBlock block) { final int id = block.getId(); diff --git a/core/src/main/java/com/boydti/fawe/util/FaweQueue.java b/core/src/main/java/com/boydti/fawe/util/FaweQueue.java index 7c7f430b..5398ef06 100644 --- a/core/src/main/java/com/boydti/fawe/util/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/FaweQueue.java @@ -14,6 +14,7 @@ public abstract class FaweQueue { public final String world; public LinkedBlockingDeque sessions; + public long modified = System.currentTimeMillis(); public FaweQueue(String world) { this.world = world; @@ -47,6 +48,10 @@ public abstract class FaweQueue { public abstract boolean regenerateChunk(int x, int z); + public void startSet(boolean parallel) {} + + public void endSet(boolean parallel) {} + /** * Gets the FaweChunk and sets the requested blocks * @return diff --git a/core/src/main/java/com/boydti/fawe/util/SetQueue.java b/core/src/main/java/com/boydti/fawe/util/SetQueue.java index 87b9423e..c2645767 100644 --- a/core/src/main/java/com/boydti/fawe/util/SetQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/SetQueue.java @@ -4,8 +4,6 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.RunnableVal2; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.LinkedBlockingDeque; @@ -55,6 +53,7 @@ public class SetQueue { @Override public void run() { if (inactiveQueues.size() == 0 && activeQueues.size() == 0) { + lastSuccess = System.currentTimeMillis(); tasks(); return; } @@ -81,21 +80,11 @@ public class SetQueue { return; } if (Settings.UNSAFE_PARALLEL_THREADS <= 1) { + SET_TASK.value2.startSet(false); SET_TASK.run(); + SET_TASK.value2.endSet(false); } else { - boolean timingsEnabled = true; - try { - Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled"); - fieldEnabled.setAccessible(true); - timingsEnabled = (boolean) fieldEnabled.get(null); - if (timingsEnabled) { - fieldEnabled.set(null, false); - Method methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled"); - methodCheck.setAccessible(true); - methodCheck.invoke(null); - } - } catch (Throwable ignore) {ignore.printStackTrace();} - try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, false); } catch (Throwable ignore) {} + SET_TASK.value2.startSet(true); ArrayList threads = new ArrayList(); for (int i = 0; i < Settings.UNSAFE_PARALLEL_THREADS; i++) { threads.add(new Thread(SET_TASK)); @@ -110,9 +99,7 @@ public class SetQueue { e.printStackTrace(); } } - try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled); - } catch (Throwable ignore) {ignore.printStackTrace();} - try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {} + SET_TASK.value2.endSet(true); } } }, 1); @@ -120,7 +107,14 @@ public class SetQueue { public void enqueue(FaweQueue queue) { inactiveQueues.remove(queue); - activeQueues.add(queue); + if (queue.size() > 0 && !activeQueues.contains(queue)) { + activeQueues.add(queue); + } + } + + public void dequeue(FaweQueue queue) { + inactiveQueues.remove(queue); + activeQueues.remove(queue); } public List getAllQueues() { @@ -150,6 +144,7 @@ public class SetQueue { while (activeQueues.size() > 0) { FaweQueue queue = activeQueues.peek(); if (queue != null && queue.size() > 0) { + queue.modified = System.currentTimeMillis(); return queue; } else { activeQueues.poll(); @@ -157,25 +152,21 @@ public class SetQueue { } if (inactiveQueues.size() > 0) { ArrayList tmp = new ArrayList<>(inactiveQueues); - if (Settings.QUEUE_MAX_WAIT != -1) { + if (Settings.QUEUE_MAX_WAIT >= 0) { long now = System.currentTimeMillis(); - if (lastSuccess == 0) { - lastSuccess = now; - } - long diff = now - lastSuccess; - if (diff > Settings.QUEUE_MAX_WAIT) { - for (FaweQueue queue : tmp) { - if (queue != null && queue.size() > 0) { - return queue; - } else { - activeQueues.poll(); + if (lastSuccess != 0) { + long diff = now - lastSuccess; + if (diff > Settings.QUEUE_MAX_WAIT) { + for (FaweQueue queue : tmp) { + if (queue != null && queue.size() > 0) { + queue.modified = now; + return queue; + } else if (now - queue.modified > Settings.QUEUE_DISCARD_AFTER) { + inactiveQueues.remove(queue); + } } + return null; } - if (diff > Settings.QUEUE_DISCARD_AFTER) { - // These edits never finished - inactiveQueues.clear(); - } - return null; } } if (Settings.QUEUE_SIZE != -1) { @@ -186,9 +177,8 @@ public class SetQueue { if (total > Settings.QUEUE_SIZE) { for (FaweQueue queue : tmp) { if (queue != null && queue.size() > 0) { + queue.modified = System.currentTimeMillis(); return queue; - } else { - activeQueues.poll(); } } } diff --git a/core/src/main/java/com/boydti/fawe/util/TaskManager.java b/core/src/main/java/com/boydti/fawe/util/TaskManager.java index 03d629a3..060fe2d8 100644 --- a/core/src/main/java/com/boydti/fawe/util/TaskManager.java +++ b/core/src/main/java/com/boydti/fawe/util/TaskManager.java @@ -48,16 +48,21 @@ public abstract class TaskManager { if (async) { async(r); } else { - if (Fawe.get().getMainThread() == Thread.currentThread()) { - if (r != null) { - r.run(); - } - } else { - task(r); - } + r.run(); } } + public void sync(final Runnable r, boolean async) { + if (async) { + async(r); + } else if (r != null && Thread.currentThread() == Fawe.get().getMainThread()){ + r.run(); + } else { + task(r); + } + } + + /** * Run a task later on the main thread * @param r diff --git a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 2ab2e236..6089baa4 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command; +import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.clipboard.LazyClipboard; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; @@ -26,6 +27,7 @@ import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -38,11 +40,13 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; @@ -110,6 +114,19 @@ public class ClipboardCommands { public List getEntities() { return editSession.getEntities(region); } + + @Override + public void forEach(RunnableVal2 task, boolean air) { + Iterator iter = region.iterator(); + while (iter.hasNext()) { + BlockVector pos = iter.next(); + BaseBlock block = getBlock((int) pos.x, (int) pos.y, (int) pos.z); + if (!air && block == EditSession.nullBlock) { + continue; + } + task.run(pos, block); + } + } }; BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard); @@ -198,13 +215,63 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) - public void paste(Player player, LocalSession session, EditSession editSession, + public void paste(Player player, LocalSession session, final EditSession editSession, + @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, + @Switch('s') boolean selectPasted) throws WorldEditException { + ClipboardHolder holder = session.getClipboard(); + if (holder.getTransform().isIdentity()) { + place(player, session, editSession, ignoreAirBlocks, atOrigin, selectPasted); + return; + } + + Clipboard clipboard = holder.getClipboard(); + Region region = clipboard.getRegion(); + Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); + Operation operation = holder + .createPaste(editSession, editSession.getWorld().getWorldData()) + .to(to) + .ignoreAirBlocks(ignoreAirBlocks) + .build(); + Operations.completeLegacy(operation); + + if (selectPasted) { + Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint())); + RegionSelector selector = new CuboidRegionSelector(player.getWorld(), to, max); + session.setRegionSelector(player.getWorld(), selector); + selector.learnChanges(); + selector.explainRegionAdjust(player, session); + } + + player.print("The clipboard has been pasted at " + to); + } + + @Command( + aliases = { "/place" }, + usage = "", + flags = "sao", + desc = "Place the clipboard's contents", + help = + "Places the clipboard's contents.\n" + + "Flags:\n" + + " -a skips air blocks\n" + + " -o pastes at the original position\n" + + " -s selects the region after pasting", + min = 0, + max = 0 + ) + + // Skips all transforms + @CommandPermissions("worldedit.clipboard.place") + @Logging(PLACEMENT) + public void place(Player player, LocalSession session, final EditSession editSession, @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, @Switch('s') boolean selectPasted) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion().clone(); Vector origin = clipboard.getOrigin(); + final Transform transform = holder.getTransform(); + // Optimize for CuboidRegion if (region instanceof CuboidRegion) { CuboidRegion cuboid = (CuboidRegion) region; Vector min = cuboid.getMinimumPoint(); @@ -213,30 +280,28 @@ public class ClipboardCommands { cuboid.setPos1(new Vector(0, 0, 0)); } Vector to = atOrigin ? origin : session.getPlacementPosition(player); - int mx = region.getMinimumPoint().getBlockX(); - int my = region.getMinimumPoint().getBlockY(); - int mz = region.getMinimumPoint().getBlockZ(); - int tx = to.getBlockX() - origin.getBlockX(); - int ty = to.getBlockY() - origin.getBlockY(); - int tz = to.getBlockZ() - origin.getBlockZ(); - Iterator iter = region.iterator(); + final int tx = to.getBlockX() - origin.getBlockX(); + final int ty = to.getBlockY() - origin.getBlockY(); + final int tz = to.getBlockZ() - origin.getBlockZ(); + // Optimize for BlockArrayClipboard if (clipboard instanceof BlockArrayClipboard) { BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; - while (iter.hasNext()) { - BlockVector loc = iter.next(); - int x = (int) loc.x; - int y = (int) loc.y; - int z = (int) loc.z; - BaseBlock block = bac.getBlockAbs(x, y, z); - if (block == EditSession.nullBlock && ignoreAirBlocks) { - continue; + bac.IMP.forEach(new RunnableVal2() { + @Override + public void run(Vector pos, BaseBlock block) { + pos.x += tx; + pos.y += ty; + pos.z += tz; + try { + editSession.setBlock(pos, block); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } } - loc.x += tx; - loc.y += ty; - loc.z += tz; - editSession.setBlock(loc, block); - } + }, !ignoreAirBlocks); } else { + // Generic optimization for unknown region type + Iterator iter = region.iterator(); while (iter.hasNext()) { BlockVector loc = iter.next(); BaseBlock block = clipboard.getBlock(loc); @@ -246,7 +311,7 @@ public class ClipboardCommands { loc.x += tx; loc.y += ty; loc.z += tz; - editSession.setBlock(loc, block); + editSession.setBlock(transform.apply(loc), block); } } // entities @@ -260,7 +325,7 @@ public class ClipboardCommands { selector.learnChanges(); selector.explainRegionAdjust(player, session); } - player.print("The clipboard has been pasted at " + to); + player.print("The clipboard has been placed at " + to); } @Command( diff --git a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 0ddde6e1..ad643f47 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -98,48 +98,37 @@ public class SchematicCommands { player.printError("Unknown schematic format: " + formatName); return; } + final Closer closer = Closer.create(); + try { + final String filePath = f.getCanonicalPath(); + final String dirPath = dir.getCanonicalPath(); - SetQueue.IMP.addTask(new Runnable() { - @Override - public void run() { - TaskManager.IMP.async(new Runnable() { - @Override - public void run() { - final Closer closer = Closer.create(); - try { - final String filePath = f.getCanonicalPath(); - final String dirPath = dir.getCanonicalPath(); + if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { + player.printError("Clipboard file could not read or it does not exist."); + } else { + final FileInputStream fis = closer.register(new FileInputStream(f)); + final BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); + final ClipboardReader reader = format.getReader(bis); - if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.printError("Clipboard file could not read or it does not exist."); - } else { - final FileInputStream fis = closer.register(new FileInputStream(f)); - final BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); - final ClipboardReader reader = format.getReader(bis); - - final WorldData worldData = player.getWorld().getWorldData(); - final Clipboard clipboard; - if (reader instanceof SchematicReader) { - clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId()); - } else { - clipboard = reader.read(player.getWorld().getWorldData()); - } - session.setClipboard(new ClipboardHolder(clipboard, worldData)); - log.info(player.getName() + " loaded " + filePath); - player.print(filename + " loaded. Paste it with //paste"); - } - } catch (final IOException e) { - player.printError("Schematic could not read or it does not exist: " + e.getMessage()); - log.log(Level.WARNING, "Failed to load a saved clipboard", e); - } finally { - try { - closer.close(); - } catch (final IOException ignored) {} - } - } - }); + final WorldData worldData = player.getWorld().getWorldData(); + final Clipboard clipboard; + if (reader instanceof SchematicReader) { + clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId()); + } else { + clipboard = reader.read(player.getWorld().getWorldData()); + } + session.setClipboard(new ClipboardHolder(clipboard, worldData)); + log.info(player.getName() + " loaded " + filePath); + player.print(filename + " loaded. Paste it with //paste"); } - }); + } catch (final IOException e) { + player.printError("Schematic could not read or it does not exist: " + e.getMessage()); + log.log(Level.WARNING, "Failed to load a saved clipboard", e); + } finally { + try { + closer.close(); + } catch (final IOException ignored) {} + } } @Command(aliases = { "save" }, usage = "[] ", desc = "Save a schematic into your clipboard") diff --git a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java index e45cd58a..c838ae11 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java @@ -19,6 +19,14 @@ package com.sk89q.worldedit.command.composition; +import com.boydti.fawe.object.FaweChunk; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.NullChangeSet; +import com.boydti.fawe.object.RegionWrapper; +import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.util.FaweQueue; +import com.boydti.fawe.util.MainUtil; +import com.boydti.fawe.util.WEManager; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.sk89q.minecraft.util.commands.CommandException; @@ -28,16 +36,25 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.function.pattern.BlockPattern; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.command.argument.CommandArgs; import com.sk89q.worldedit.util.command.composition.CommandExecutor; import com.sk89q.worldedit.util.command.composition.SimpleCommand; +import java.lang.reflect.Field; +import java.util.HashSet; import java.util.List; @@ -82,60 +99,60 @@ public class SelectionCommand extends SimpleCommand { Operation operation = operationFactory.createFromContext(editContext); // Shortcut -// if (selection instanceof CuboidRegion && editSession.hasFastMode() && operation instanceof RegionVisitor) { -// CuboidRegion cuboid = (CuboidRegion) selection; -// RegionFunction function = ((RegionVisitor) operation).function; -// RegionWrapper current = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint()); -// FawePlayer fp = FawePlayer.wrap(player); -// HashSet mask = WEManager.IMP.getMask(fp); -// -// if (function instanceof BlockReplace && mask.size() == 1 && mask.iterator().next().contains(current)) { -// try { -// BlockReplace replace = ((BlockReplace) function); -// Field field = replace.getClass().getDeclaredField("pattern"); -// field.setAccessible(true); -// Pattern pattern = (Pattern) field.get(replace); -// if (pattern instanceof BlockPattern) { -// BaseBlock block = ((BlockPattern) pattern).getBlock(); -// final FaweQueue queue = editSession.getQueue(); -// final int minY = cuboid.getMinimumY(); -// final int maxY = cuboid.getMaximumY(); -// -// final int id = block.getId(); -// final byte data = (byte) block.getData(); -// final FaweChunk fc = queue.getChunk(0, 0); -// fc.fillCuboid(0, 15, minY, maxY, 0, 15, id, data); -// -// int bcx = (current.minX) >> 4; -// int bcz = (current.minZ) >> 4; -// -// int tcx = (current.maxX) >> 4; -// int tcz = (current.maxZ) >> 4; -// // [chunkx, chunkz, pos1x, pos1z, pos2x, pos2z, isedge] -// MainUtil.chunkTaskSync(current, new RunnableVal() { -// @Override -// public void run(int[] value) { -// FaweChunk newChunk; -// if (value[6] == 0) { -// newChunk = fc.copy(true); -// newChunk.setLoc(queue, value[0], value[1]); -// } else { -// newChunk = queue.getChunk(value[0], value[1]); -// newChunk.fillCuboid(value[2] & 15, value[4] & 15, minY, maxY, value[3] & 15, value[5] & 15, id, data); -// } -// newChunk.addToQueue(); -// } -// }); -// queue.enqueue(); -// editSession.setChangeSet(new NullChangeSet()); -// actor.print("[FAWE] Finished queueing " + cuboid.getArea() + " blocks."); -// return null; -// } -// } catch (Throwable e) { -// e.printStackTrace(); -// } -// } -// } + if (selection instanceof CuboidRegion && editSession.hasFastMode() && operation instanceof RegionVisitor) { + CuboidRegion cuboid = (CuboidRegion) selection; + RegionFunction function = ((RegionVisitor) operation).function; + RegionWrapper current = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint()); + FawePlayer fp = FawePlayer.wrap(player); + HashSet mask = WEManager.IMP.getMask(fp); + + if (function instanceof BlockReplace && mask.size() == 1 && mask.iterator().next().contains(current)) { + try { + BlockReplace replace = ((BlockReplace) function); + Field field = replace.getClass().getDeclaredField("pattern"); + field.setAccessible(true); + Pattern pattern = (Pattern) field.get(replace); + if (pattern instanceof BlockPattern) { + BaseBlock block = ((BlockPattern) pattern).getBlock(); + final FaweQueue queue = editSession.getQueue(); + final int minY = cuboid.getMinimumY(); + final int maxY = cuboid.getMaximumY(); + + final int id = block.getId(); + final byte data = (byte) block.getData(); + final FaweChunk fc = queue.getChunk(0, 0); + fc.fillCuboid(0, 15, minY, maxY, 0, 15, id, data); + + int bcx = (current.minX) >> 4; + int bcz = (current.minZ) >> 4; + + int tcx = (current.maxX) >> 4; + int tcz = (current.maxZ) >> 4; + // [chunkx, chunkz, pos1x, pos1z, pos2x, pos2z, isedge] + MainUtil.chunkTaskSync(current, new RunnableVal() { + @Override + public void run(int[] value) { + FaweChunk newChunk; + if (value[6] == 0) { + newChunk = fc.copy(true); + newChunk.setLoc(queue, value[0], value[1]); + } else { + newChunk = queue.getChunk(value[0], value[1]); + newChunk.fillCuboid(value[2] & 15, value[4] & 15, minY, maxY, value[3] & 15, value[5] & 15, id, data); + } + newChunk.addToQueue(); + } + }); + queue.enqueue(); + editSession.setChangeSet(new NullChangeSet()); + actor.print("[FAWE] Finished queueing " + cuboid.getArea() + " blocks."); + return null; + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + } Operations.completeBlindly(operation); List messages = Lists.newArrayList(); diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/FaweForge.java b/forge1710/src/main/java/com/boydti/fawe/forge/FaweForge.java index 50a77f8c..a7f109d6 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/FaweForge.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/FaweForge.java @@ -130,7 +130,7 @@ public class FaweForge implements IFawe { @Override public void startMetrics() { try { - ForgeMetrics metrics = new ForgeMetrics("FastAsyncWorldEdit", "3.4.1"); + ForgeMetrics metrics = new ForgeMetrics("FastAsyncWorldEdit", "3.4.2"); metrics.start(); debug("[FAWE] &6Metrics enabled."); } catch (Throwable e) { diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java index 0a62143b..1340cad6 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -19,7 +19,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import org.apache.logging.log4j.Logger; -@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.1", acceptableRemoteVersions = "*") +@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.2", acceptableRemoteVersions = "*") public class ForgeMain { private static FaweForge IMP; private Logger logger; diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index e643eb07..2775c775 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -335,7 +335,7 @@ public class ForgeQueue_All extends FaweQueue { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) { diff --git a/forge1710/src/main/resources/mcmod.info b/forge1710/src/main/resources/mcmod.info index 3185d6e6..b03148c8 100644 --- a/forge1710/src/main/resources/mcmod.info +++ b/forge1710/src/main/resources/mcmod.info @@ -2,7 +2,7 @@ "modid": "com.boydti.fawe", "name": "FastAsyncWorldEdit", "description": "Extreme WorldEdit optimizations, no lag, low memory usage, area + tile + entity limits, block logging + rollback", - "version": "3.4.1", + "version": "3.4.2", "mcVersion": "1.7.10", "dependencies": [ "WorldEdit" diff --git a/forge189/src/main/java/com/boydti/fawe/forge/FaweForge.java b/forge189/src/main/java/com/boydti/fawe/forge/FaweForge.java index 80237ed9..8da67b62 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/FaweForge.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/FaweForge.java @@ -131,7 +131,7 @@ public class FaweForge implements IFawe { @Override public void startMetrics() { try { - com.boydti.fawe.forge.ForgeMetrics metrics = new com.boydti.fawe.forge.ForgeMetrics("FastAsyncWorldEdit", "3.4.1"); + com.boydti.fawe.forge.ForgeMetrics metrics = new com.boydti.fawe.forge.ForgeMetrics("FastAsyncWorldEdit", "3.4.2"); metrics.start(); debug("[FAWE] &6Metrics enabled."); } catch (Throwable e) { diff --git a/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java b/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java index 199407ff..25602dfa 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/ForgeMain.java @@ -19,7 +19,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.PlayerEvent; import org.apache.logging.log4j.Logger; -@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.1", acceptableRemoteVersions = "*") +@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.2", acceptableRemoteVersions = "*") public class ForgeMain { private static com.boydti.fawe.forge.FaweForge IMP; private Logger logger; diff --git a/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java b/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java index 2300ffb0..e9f68388 100644 --- a/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java +++ b/forge189/src/main/java/com/boydti/fawe/forge/v0/ForgeQueue_All.java @@ -290,7 +290,7 @@ public class ForgeQueue_All extends FaweQueue { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) { diff --git a/pom.xml b/pom.xml index 5d7ac1b3..62d0b3c2 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ UTF-8 FastAsyncWorldEdit - 3.4.1 + 3.4.2 FastAsyncWorldEdit jar diff --git a/sponge/src/main/java/com/boydti/fawe/sponge/SpongeMain.java b/sponge/src/main/java/com/boydti/fawe/sponge/SpongeMain.java index 12ca68e5..c2379da2 100644 --- a/sponge/src/main/java/com/boydti/fawe/sponge/SpongeMain.java +++ b/sponge/src/main/java/com/boydti/fawe/sponge/SpongeMain.java @@ -18,7 +18,7 @@ import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.profile.GameProfileManager; import org.spongepowered.api.world.World; -@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.4.1", authors = "Empire92") +@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.4.2", authors = "Empire92") public class SpongeMain { public PluginContainer plugin; diff --git a/sponge/src/main/java/com/boydti/fawe/v1_8/SpongeQueue_1_8.java b/sponge/src/main/java/com/boydti/fawe/v1_8/SpongeQueue_1_8.java index 6768c00b..136ec30d 100644 --- a/sponge/src/main/java/com/boydti/fawe/v1_8/SpongeQueue_1_8.java +++ b/sponge/src/main/java/com/boydti/fawe/v1_8/SpongeQueue_1_8.java @@ -119,7 +119,7 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 { @Override public void run() { final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING; - TaskManager.IMP.task(new Runnable() { + TaskManager.IMP.sync(new Runnable() { @Override public void run() { if (!result) {