diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index 8335dca2..804e8c26 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -204,6 +204,8 @@ public class FaweBukkit implements IFawe, Listener { debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]); debug("Fallback placer: " + BukkitQueue_All.class); debug("======================================="); + debug("Download the version of FAWE for your platform"); + debug("======================================="); hasNMS = false; } return new BukkitQueue_All(world); diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java index 909d57c2..c419c14d 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/v0/BukkitQueue_0.java @@ -6,14 +6,15 @@ import com.boydti.fawe.example.CharFaweChunk; import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweQueue; +import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.SetQueue; +import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -21,10 +22,12 @@ import java.util.concurrent.ConcurrentLinkedDeque; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; +import org.bukkit.WorldCreator; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.WorldInitEvent; public abstract class BukkitQueue_0 extends NMSMappedFaweQueue implements Listener { @@ -62,8 +65,8 @@ public abstract class BukkitQueue_0 extends NMSMa long pair = MathMan.pairInt(chunk.getX(), chunk.getZ()); for (FaweQueue queue : queues) { if (queue.getWorldName().equals(world)) { - HashSet relighting = ((NMSMappedFaweQueue) queue).relighting; - if (!relighting.isEmpty() && relighting.contains(pair)) { + Map relighting = ((NMSMappedFaweQueue) queue).relighting; + if (!relighting.isEmpty() && relighting.containsKey(pair)) { event.setCancelled(true); return; } @@ -71,6 +74,28 @@ public abstract class BukkitQueue_0 extends NMSMa } } + private static boolean disableChunkLoad = false; + + @EventHandler + public static void onWorldLoad(WorldInitEvent event) { + if (disableChunkLoad) { + World world = event.getWorld(); + world.setKeepSpawnInMemory(false); + } + } + + public World createWorld(final WorldCreator creator) { + World world = TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(World value) { + disableChunkLoad = true; + this.value = creator.createWorld(); + disableChunkLoad = false; + } + }); + return world; + } + public void setupAdapter(BukkitImplAdapter adapter) { try { WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); diff --git a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java index f8118ebc..9e82ceef 100644 --- a/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java +++ b/bukkit0/src/main/java/com/boydti/fawe/bukkit/wrapper/AsyncWorld.java @@ -4,6 +4,7 @@ import com.boydti.fawe.FaweAPI; import com.boydti.fawe.bukkit.v0.BukkitQueue_0; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.RunnableVal; +import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.TaskManager; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -27,6 +28,7 @@ import org.bukkit.Sound; import org.bukkit.TreeType; import org.bukkit.World; import org.bukkit.WorldBorder; +import org.bukkit.WorldCreator; import org.bukkit.WorldType; import org.bukkit.block.Biome; import org.bukkit.block.Block; @@ -47,21 +49,36 @@ import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; /** - * Modify the world from an async thread
- * - Any Chunk/Block/BlockState objects returned should also be thread safe
- * - Use world.commit() to execute the changes
- * - Don't rely on autoQueue as behavior is determined by the settings.yml
+ * Modify the world from an async thread
+ * - Use world.commit() to execute all the changes
+ * - Any Chunk/Block/BlockState objects returned should also be safe to use from the same async thread
+ * - Only block read,write and biome write are fast, other methods will perform slower async
+ * - + * @see #wrap(org.bukkit.World) + * @see #create(org.bukkit.WorldCreator) */ public class AsyncWorld implements World { - public final World parent; - public final FaweQueue queue; + private final World parent; + private final FaweQueue queue; private BukkitImplAdapter adapter; + /** + * @deprecated use {@link #wrap(org.bukkit.World)} instead + * @param parent Parent world + * @param autoQueue + */ + @Deprecated public AsyncWorld(World parent, boolean autoQueue) { this(parent, FaweAPI.createQueue(parent.getName(), autoQueue)); } + /** + * @deprecated use {@link #wrap(org.bukkit.World)} instead + * @param parent + * @param queue + */ + @Deprecated public AsyncWorld(World parent, FaweQueue queue) { this.parent = parent; this.queue = queue; @@ -79,6 +96,11 @@ public class AsyncWorld implements World { } } + /** + * Wrap a world for async usage + * @param world + * @return + */ public static AsyncWorld wrap(World world) { if (world instanceof AsyncWorld) { return (AsyncWorld) world; @@ -86,6 +108,28 @@ public class AsyncWorld implements World { return new AsyncWorld(world, false); } + public World getParent() { + return parent; + } + + public FaweQueue getQueue() { + return queue; + } + + /** + * Create a world async (untested) + * - Only optimized for 1.10 + * @param creator + * @return + */ + public static AsyncWorld create(final WorldCreator creator) { + long start = System.currentTimeMillis(); + BukkitQueue_0 queue = (BukkitQueue_0) SetQueue.IMP.getNewQueue(creator.name(), true, false); + World world = queue.createWorld(creator); + System.out.println(System.currentTimeMillis() - start); + return wrap(world); + } + public void enqueue() { queue.enqueue(); } diff --git a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java index 4c8b6514..edb88fca 100644 --- a/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java +++ b/bukkit110/src/main/java/com/boydti/fawe/bukkit/v1_10/BukkitQueue_1_10.java @@ -18,6 +18,7 @@ import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.internal.Constants; +import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.ArrayList; @@ -44,22 +45,37 @@ import net.minecraft.server.v1_10_R1.EntityPlayer; import net.minecraft.server.v1_10_R1.EntityTracker; import net.minecraft.server.v1_10_R1.EntityTrackerEntry; import net.minecraft.server.v1_10_R1.EntityTypes; +import net.minecraft.server.v1_10_R1.EnumDifficulty; +import net.minecraft.server.v1_10_R1.EnumGamemode; import net.minecraft.server.v1_10_R1.IBlockData; +import net.minecraft.server.v1_10_R1.IDataManager; +import net.minecraft.server.v1_10_R1.MinecraftServer; import net.minecraft.server.v1_10_R1.NBTTagCompound; import net.minecraft.server.v1_10_R1.NibbleArray; import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy; import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk; import net.minecraft.server.v1_10_R1.PlayerChunk; import net.minecraft.server.v1_10_R1.PlayerChunkMap; +import net.minecraft.server.v1_10_R1.ServerNBTManager; import net.minecraft.server.v1_10_R1.TileEntity; +import net.minecraft.server.v1_10_R1.WorldData; +import net.minecraft.server.v1_10_R1.WorldManager; import net.minecraft.server.v1_10_R1.WorldServer; +import net.minecraft.server.v1_10_R1.WorldSettings; +import net.minecraft.server.v1_10_R1.WorldType; +import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.World.Environment; +import org.bukkit.WorldCreator; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_10_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_10_R1.CraftServer; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.world.WorldInitEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.generator.ChunkGenerator; public class BukkitQueue_1_10 extends BukkitQueue_0 { @@ -82,6 +98,69 @@ public class BukkitQueue_1_10 extends BukkitQueue_0() { + @Override + public void run(World value) { + server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld())); + server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld())); + this.value = internal.getWorld(); + } + }); + } + @Override public ChunkSection[] getCachedSections(World world, int cx, int cz) { CraftChunk chunk = (CraftChunk) world.getChunkAt(cx, cz); diff --git a/core/src/main/java/com/boydti/fawe/Fawe.java b/core/src/main/java/com/boydti/fawe/Fawe.java index 8967fbba..fdf2a426 100644 --- a/core/src/main/java/com/boydti/fawe/Fawe.java +++ b/core/src/main/java/com/boydti/fawe/Fawe.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BlockData; import com.sk89q.worldedit.command.BrushCommands; import com.sk89q.worldedit.command.ClipboardCommands; +import com.sk89q.worldedit.command.FlattenedClipboardTransform; import com.sk89q.worldedit.command.HistoryCommands; import com.sk89q.worldedit.command.NavigationCommands; import com.sk89q.worldedit.command.RegionCommands; @@ -295,6 +296,8 @@ public class Fawe { RecursiveVisitor.inject(); // Optimizations RegionVisitor.inject(); // Translations + Optimizations ExtentEntityCopy.inject(); // Async entity create fix + // Transforms + FlattenedClipboardTransform.inject(); // public access // Entity create/remove EntityCreate.inject(); // Optimizations EntityRemove.inject(); // Optimizations diff --git a/core/src/main/java/com/boydti/fawe/config/BBC.java b/core/src/main/java/com/boydti/fawe/config/BBC.java index 8a3fe323..0d20aaee 100644 --- a/core/src/main/java/com/boydti/fawe/config/BBC.java +++ b/core/src/main/java/com/boydti/fawe/config/BBC.java @@ -1,6 +1,7 @@ package com.boydti.fawe.config; import com.boydti.fawe.Fawe; +import com.boydti.fawe.configuration.MemorySection; import com.boydti.fawe.configuration.file.YamlConfiguration; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.util.MainUtil; @@ -255,24 +256,21 @@ public enum BBC { final HashSet captions = new HashSet<>(); boolean changed = false; for (final String key : keys) { - if (!yml.isString(key)) { - if (!allCats.contains(key)) { - toRemove.add(key); - } + final Object value = yml.get(key); + if (value instanceof MemorySection) { continue; } final String[] split = key.split("\\."); final String node = split[split.length - 1].toUpperCase(); final BBC caption = allNames.contains(node) ? valueOf(node) : null; if (caption != null) { - final String value = yml.getString(key); if (!split[0].equalsIgnoreCase(caption.cat)) { changed = true; yml.set(key, null); yml.set(caption.cat + "." + caption.name().toLowerCase(), value); } captions.add(caption); - caption.s = value; + caption.s = (String) value; } else { toRemove.add(key); } 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 7289ad58..d3f096b9 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -241,4 +241,4 @@ public class Settings extends Config { } return limit; } -} +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java index 1f6c86ec..adebbedf 100644 --- a/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/example/CharFaweChunk.java @@ -182,7 +182,46 @@ public abstract class CharFaweChunk extends FaweChunk { } @Override - public void setBlock(final int x, final int y, final int z, final int id, byte data) { + public void setBlock(int x, int y, int z, int id) { + final int i = FaweCache.CACHE_I[y][x][z]; + final int j = FaweCache.CACHE_J[y][x][z]; + char[] vs = this.ids[i]; + if (vs == null) { + vs = this.ids[i] = new char[4096]; + this.count[i]++; + } else if (vs[j] == 0) { + this.count[i]++; + } + switch (id) { + case 0: + this.air[i]++; + vs[j] = (char) 1; + return; + case 11: + case 39: + case 40: + case 51: + case 74: + case 89: + case 122: + case 124: + case 138: + case 169: + case 213: + case 130: + case 76: + case 62: + case 50: + case 10: + this.relight[i]++; + default: + vs[j] = (char) (id << 4); + return; + } + } + + @Override + public void setBlock(final int x, final int y, final int z, final int id, int data) { final int i = FaweCache.CACHE_I[y][x][z]; final int j = FaweCache.CACHE_J[y][x][z]; char[] vs = this.ids[i]; diff --git a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java index b44a3984..f9164cf6 100644 --- a/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/MappedFaweQueue.java @@ -126,10 +126,7 @@ public abstract class MappedFaweQueue extends FaweQueue { private int lastZ = Integer.MIN_VALUE; @Override - public boolean setBlock(int x, int y, int z, short id, byte data) { - if ((y > 255) || (y < 0)) { - return false; - } + public boolean setBlock(int x, int y, int z, int id, int data) { int cx = x >> 4; int cz = z >> 4; if (cx != lastX || cz != lastZ) { @@ -153,6 +150,31 @@ public abstract class MappedFaweQueue extends FaweQueue { return true; } + @Override + public boolean setBlock(int x, int y, int z, int id) { + int cx = x >> 4; + int cz = z >> 4; + if (cx != lastX || cz != lastZ) { + lastX = cx; + lastZ = cz; + long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL; + lastWrappedChunk = this.blocks.get(pair); + if (lastWrappedChunk == null) { + lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4); + lastWrappedChunk.setBlock(x & 15, y, z & 15, id); + FaweChunk previous = this.blocks.put(pair, lastWrappedChunk); + if (previous == null) { + chunks.add(lastWrappedChunk); + return true; + } + this.blocks.put(pair, previous); + lastWrappedChunk = previous; + } + } + lastWrappedChunk.setBlock(x & 15, y, z & 15, id); + return true; + } + @Override public void setTile(int x, int y, int z, CompoundTag tag) { if ((y > 255) || (y < 0)) { diff --git a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java index f3084704..692c2366 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -9,10 +9,10 @@ import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.TaskManager; import com.sk89q.jnbt.CompoundTag; import java.util.Collection; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public abstract class NMSMappedFaweQueue extends MappedFaweQueue { public NMSMappedFaweQueue(String world) { @@ -24,7 +24,7 @@ public abstract class NMSMappedFaweQueue ex return relighting.contains(pair) || blocks.contains(pair); } - public final HashSet relighting = new HashSet<>(); + public final ConcurrentHashMap relighting = new ConcurrentHashMap<>(); @Override public void sendChunk(final FaweChunk fc, RelightMode mode) { @@ -36,7 +36,7 @@ public abstract class NMSMappedFaweQueue ex @Override public void run() { final long pair = fc.longHash(); - relighting.add(pair); + relighting.put(pair, pair); final boolean result = finalMode == RelightMode.NONE || fixLighting(fc, finalMode); TaskManager.IMP.taskSyncNow(new Runnable() { @Override @@ -47,7 +47,7 @@ public abstract class NMSMappedFaweQueue ex CHUNK chunk = (CHUNK) fc.getChunk(); refreshChunk(getWorld(), chunk); relighting.remove(pair); - if (relighting.isEmpty()) { + if (relighting.isEmpty() && chunks.isEmpty()) { runTasks(); } } diff --git a/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java b/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java index 96ccf7aa..aab2f865 100644 --- a/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/ChangeSetFaweQueue.java @@ -23,7 +23,7 @@ public class ChangeSetFaweQueue extends DelegateFaweQueue { } @Override - public boolean setBlock(int x, int y, int z, short id, byte data) { + public boolean setBlock(int x, int y, int z, int id, int data) { if (super.setBlock(x, y, z, id, data)) { int combinedFrom = getParent().getCombinedId4Data(x, y, z); if (FaweCache.hasNBT(combinedFrom >> 4)) { diff --git a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java index 2cb8b5a5..375eb390 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweChunk.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweChunk.java @@ -185,7 +185,11 @@ public abstract class FaweChunk { public abstract void removeEntity(UUID uuid); - public abstract void setBlock(final int x, final int y, final int z, final int id, final byte data); + public void setBlock(int x, int y, int z, int id) { + setBlock(x, y, z, id, 0); + } + + public abstract void setBlock(final int x, final int y, final int z, final int id, final int data); public abstract Set getEntities(); diff --git a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java index a3971814..27b60abe 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -103,7 +103,19 @@ public abstract class FaweQueue { public void optimize() {} - public abstract boolean setBlock(final int x, final int y, final int z, final short id, final byte data); + public abstract boolean setBlock(final int x, final int y, final int z, final int id, final int data); + + public boolean setBlock(int x, int y, int z, int id) { + return setBlock(x, y, z, id, 0); + } + + public boolean setBlock(int x, int y, int z, int id, int data, CompoundTag nbt) { + if (nbt != null) { + MainUtil.setPosition(nbt, x, y, z); + setTile(x, y, z, nbt); + } + return setBlock(x, y, z, id, data); + } public abstract void setTile(int x, int y, int z, CompoundTag tag); @@ -195,6 +207,13 @@ public abstract class FaweQueue { * Lock the thread until the queue is empty */ public void flush() { + flush(Integer.MAX_VALUE); + } + + /** + * Lock the thread until the queue is empty + */ + public void flush(int time) { if (size() > 0) { if (Fawe.get().isMainThread()) { SetQueue.IMP.flush(this); @@ -207,7 +226,7 @@ public abstract class FaweQueue { TaskManager.IMP.notify(running); } }); - TaskManager.IMP.wait(running, 10000); + TaskManager.IMP.wait(running, time); } } } diff --git a/core/src/main/java/com/boydti/fawe/object/MaskedFaweQueue.java b/core/src/main/java/com/boydti/fawe/object/MaskedFaweQueue.java index 3264a2a3..9320cae5 100644 --- a/core/src/main/java/com/boydti/fawe/object/MaskedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/MaskedFaweQueue.java @@ -32,7 +32,7 @@ public class MaskedFaweQueue extends DelegateFaweQueue { } @Override - public boolean setBlock(int x, int y, int z, short id, byte data) { + public boolean setBlock(int x, int y, int z, int id, int data) { if (WEManager.IMP.maskContains(mask, x, z)) { return super.setBlock(x, y, z, id, data); } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java index 29a00960..73701d47 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweChangeSet.java @@ -252,9 +252,10 @@ public abstract class FaweChangeSet implements ChangeSet { } catch (Throwable e) { MainUtil.handleError(e); } finally { - waiting.decrementAndGet(); - synchronized (lock) { - lock.notifyAll(); + if (waiting.decrementAndGet() <= 0) { + synchronized (lock) { + lock.notifyAll(); + } } } } diff --git a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java index bacc9640..2471c195 100644 --- a/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java +++ b/core/src/main/java/com/boydti/fawe/object/changeset/FaweStreamChangeSet.java @@ -103,7 +103,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet { stream.write((combinedTo) & 0xff); stream.write(((combinedTo) >> 8) & 0xff); } - catch (IOException e) { + catch (Throwable e) { MainUtil.handleError(e); } } diff --git a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java index 7a57632a..80cc64d8 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/FastWorldEditExtent.java @@ -1,6 +1,5 @@ package com.boydti.fawe.object.extent; -import com.boydti.fawe.FaweCache; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.ReflectionUtils; @@ -107,30 +106,286 @@ public class FastWorldEditExtent extends AbstractDelegateExtent { @Override public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException { - final short id = (short) block.getId(); - byte data = (byte) block.getData(); - final int x = location.getBlockX(); - final int y = location.getBlockY(); - final int z = location.getBlockZ(); - switch (id) { - case 68: { - if (data == 0) { - data = 2; - } - } + final int y = (int) location.y; + switch (y) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + case 58: + case 59: + case 60: + case 61: + case 62: case 63: - if (block.hasNbtData() && !MainUtil.isValidSign(block.getNbtData())) { - queue.setBlock(x, y, z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0); - return true; - } + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 91: + case 92: + case 93: + case 94: + case 95: + case 96: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + case 123: + case 124: + case 125: + case 126: + case 127: + case 128: + case 129: + case 130: + case 131: + case 132: + case 133: + case 134: + case 135: + case 136: + case 137: + case 138: + case 139: + case 140: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: + case 148: + case 149: + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + case 160: + case 161: + case 162: + case 163: + case 164: + case 165: + case 166: + case 167: + case 168: + case 169: + case 170: + case 171: + case 172: + case 173: + case 174: + case 175: + case 176: + case 177: + case 178: + case 179: + case 180: + case 181: + case 182: + case 183: + case 184: + case 185: + case 186: + case 187: + case 188: + case 189: + case 190: + case 191: + case 192: + case 193: + case 194: + case 195: + case 196: + case 197: + case 198: + case 199: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + case 207: + case 208: + case 209: + case 210: + case 211: + case 212: + case 213: + case 214: + case 215: + case 216: + case 217: + case 218: + case 219: + case 220: + case 221: + case 222: + case 223: + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + case 231: + case 232: + case 233: + case 234: + case 235: + case 236: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: + case 248: + case 249: + case 250: + case 251: + case 252: + case 253: + case 254: + case 255: + break; + default: + return false; + } + final int x = (int) location.x; + final int z = (int) location.z; + final short id = (short) block.getId(); + switch (id) { + case 63: + // Fix for signs + return queue.setBlock(x, y, z, id, (byte) block.getData(), block.hasNbtData() && !MainUtil.isValidSign(block.getNbtData()) ? null : block.getNbtData()); + case 65: + case 68: case 54: case 146: case 61: - { + // Fix for default block rotation + byte data = (byte) block.getData(); if (data == 0) { data = 2; } - } + return queue.setBlock(x, y, z, id, data, block.getNbtData()); case 130: case 142: case 27: @@ -161,23 +416,73 @@ public class FastWorldEditExtent extends AbstractDelegateExtent { case 29: case 33: case 151: - case 178: { - if (block.hasNbtData()) { - CompoundTag nbt = block.getNbtData(); - MainUtil.setPosition(nbt, x, y, z); - queue.setTile(x, y, z, nbt); - } - queue.setBlock(x, y, z, id, data); - return true; - } - case 65: { - if (data == 0) { - data = 2; - } - } + case 178: + // Tile + return queue.setBlock(x, y, z, id, (byte) block.getData(), block.getNbtData()); + case 0: + case 2: + case 4: + case 13: + case 14: + case 15: + case 20: + case 21: + case 22: + case 30: + case 32: + case 37: + case 39: + case 40: + case 41: + case 42: + case 45: + case 46: + case 47: + case 48: + case 49: + case 51: + case 56: + case 57: + case 58: + case 60: + case 7: + case 11: + case 73: + case 74: + case 79: + case 80: + case 81: + case 82: + case 83: + case 85: + case 87: + case 88: + case 101: + case 102: + case 103: + case 110: + case 112: + case 113: + case 121: + case 122: + case 129: + case 133: + case 165: + case 166: + case 169: + case 170: + case 172: + case 173: + case 174: + case 188: + case 189: + case 190: + case 191: + case 192: + // No data + return queue.setBlock(x, y, z, id); default: { - queue.setBlock(x, y, z, id, data); - return true; + return queue.setBlock(x, y, z, id, (byte) block.getData()); } } } diff --git a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java index 0b323229..04afc3a2 100644 --- a/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/util/DelegateFaweQueue.java @@ -93,7 +93,7 @@ public class DelegateFaweQueue extends FaweQueue { } @Override - public boolean setBlock(int x, int y, int z, short id, byte data) { + public boolean setBlock(int x, int y, int z, int id, int data) { return parent.setBlock(x, y, z, id, data); } diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index 9f7d0691..cb3f0046 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -127,7 +127,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -1028,20 +1027,14 @@ public class EditSession implements Extent { queue.enqueue(); } else { queue.dequeue(); + return; } if (getChangeSet() != null) { if (Settings.HISTORY.COMBINE_STAGES && queue.size() > 0) { if (Fawe.get().isMainThread()) { SetQueue.IMP.flush(queue); } else { - final AtomicBoolean running = new AtomicBoolean(true); - queue.addNotifyTask(new Runnable() { - @Override - public void run() { - TaskManager.IMP.notify(running); - } - }); - TaskManager.IMP.wait(running, Settings.QUEUE.DISCARD_AFTER_MS); + queue.flush(); } } ((FaweChangeSet) getChangeSet()).flush(); diff --git a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index d6fdd96d..66d84a2f 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -288,7 +288,6 @@ public class BrushCommands { public void command(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius, CommandContext args) throws WorldEditException { BrushTool tool = session.getBrushTool(player.getItemInHand()); String cmd = args.getJoinedStrings(1); - System.out.println(cmd); tool.setBrush(new CommandBrush(player, cmd, radius), "worldedit.brush.copy"); BBC.BRUSH_COMMAND.send(player, cmd); } diff --git a/core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java new file mode 100644 index 00000000..1f52bda4 --- /dev/null +++ b/core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java @@ -0,0 +1,146 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.command; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.math.transform.AffineTransform; +import com.sk89q.worldedit.math.transform.CombinedTransform; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.registry.WorldData; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper class to 'bake' a transform into a clipboard. + * + *

This class needs a better name and may need to be made more generic.

+ * + * @see Clipboard + * @see Transform + */ +public class FlattenedClipboardTransform { + + private final Clipboard original; + private final Transform transform; + private final WorldData worldData; + + /** + * Create a new instance. + * + * @param original the original clipboard + * @param transform the transform + * @param worldData the world data instance + */ + private FlattenedClipboardTransform(Clipboard original, Transform transform, WorldData worldData) { + checkNotNull(original); + checkNotNull(transform); + checkNotNull(worldData); + this.original = original; + this.transform = transform; + this.worldData = worldData; + } + + /** + * Get the transformed region. + * + * @return the transformed region + */ + public Region getTransformedRegion() { + Region region = original.getRegion(); + Vector minimum = region.getMinimumPoint(); + Vector maximum = region.getMaximumPoint(); + + Transform transformAround = + new CombinedTransform( + new AffineTransform().translate(original.getOrigin().multiply(-1)), + transform, + new AffineTransform().translate(original.getOrigin())); + + Vector[] corners = new Vector[] { + minimum, + maximum, + minimum.setX(maximum.getX()), + minimum.setY(maximum.getY()), + minimum.setZ(maximum.getZ()), + maximum.setX(minimum.getX()), + maximum.setY(minimum.getY()), + maximum.setZ(minimum.getZ()) }; + + for (int i = 0; i < corners.length; i++) { + corners[i] = transformAround.apply(corners[i]); + } + + Vector newMinimum = corners[0]; + Vector newMaximum = corners[0]; + + for (int i = 1; i < corners.length; i++) { + newMinimum = Vector.getMinimum(newMinimum, corners[i]); + newMaximum = Vector.getMaximum(newMaximum, corners[i]); + } + + // After transformation, the points may not really sit on a block, + // so we should expand the region for edge cases + newMinimum = newMinimum.setX(Math.floor(newMinimum.getX())); + newMinimum = newMinimum.setY(Math.floor(newMinimum.getY())); + newMinimum = newMinimum.setZ(Math.floor(newMinimum.getZ())); + + newMaximum = newMaximum.setX(Math.ceil(newMaximum.getX())); + newMaximum = newMaximum.setY(Math.ceil(newMaximum.getY())); + newMaximum = newMaximum.setZ(Math.ceil(newMaximum.getZ())); + + return new CuboidRegion(newMinimum, newMaximum); + } + + /** + * Create an operation to copy from the original clipboard to the given extent. + * + * @param target the target + * @return the operation + */ + public Operation copyTo(Extent target) { + BlockTransformExtent extent = new BlockTransformExtent(original, transform, worldData.getBlockRegistry()); + ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin()); + copy.setTransform(transform); + return copy; + } + + /** + * Create a new instance to bake the transform with. + * + * @param original the original clipboard + * @param transform the transform + * @param worldData the world data instance + * @return a builder + */ + public static FlattenedClipboardTransform transform(Clipboard original, Transform transform, WorldData worldData) { + return new FlattenedClipboardTransform(original, transform, worldData); + } + + public static Class inject() { + return FlattenedClipboardTransform.class; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java index 78dd075f..685d1a75 100644 --- a/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java +++ b/core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicWriter.java @@ -129,13 +129,9 @@ public class SchematicWriter implements ClipboardWriter { throw new IllegalArgumentException("Length of region too large for a .schematic"); } - System.out.println(clipboard.getMinimumPoint()); - System.out.println(clipboard.getMaximumPoint()); - // ==================================================================== // Metadata // ==================================================================== - HashMap schematic = new HashMap(); schematic.put("Width", new ShortTag((short) width)); schematic.put("Length", new ShortTag((short) length)); diff --git a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java index 17d37ccc..42573396 100644 --- a/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java +++ b/forge1710/src/main/java/com/boydti/fawe/forge/v0/ForgeChunk_All.java @@ -34,7 +34,7 @@ public class ForgeChunk_All extends CharFaweChunk { } @Override - public void setBlock(int x, int y, int z, int id, byte data) { + public void setBlock(int x, int y, int z, int id, int data) { int i = FaweCache.CACHE_I[y][x][z]; int j = FaweCache.CACHE_J[y][x][z]; byte[] vs = this.byteIds[i];