From 28f3be56b32fd0e5321fa6187a5e8d7fb8ae055c Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 21 Dec 2018 00:49:15 +0000 Subject: [PATCH] Fix schematic creation Seems fairly ugly, but only because the format requires the blocks be inputted in that exact order, and it prevents us from having to cache the blocks per chunk to then insert into the relevant tags. --- .../bukkit/util/BukkitSchematicHandler.java | 188 +++++------ .../plot/util/SchematicHandler.java | 313 +++++++++--------- 2 files changed, 243 insertions(+), 258 deletions(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitSchematicHandler.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitSchematicHandler.java index acf18de85..5ae07bfba 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitSchematicHandler.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitSchematicHandler.java @@ -1,7 +1,6 @@ package com.github.intellectualsites.plotsquared.bukkit.util; import com.github.intellectualsites.plotsquared.bukkit.object.schematic.StateWrapper; -import com.github.intellectualsites.plotsquared.plot.object.ChunkLoc; import com.github.intellectualsites.plotsquared.plot.object.Location; import com.github.intellectualsites.plotsquared.plot.object.RegionWrapper; import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; @@ -13,12 +12,10 @@ import com.sk89q.jnbt.*; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BaseBlock; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; import java.io.ByteArrayOutputStream; import java.util.*; +import java.util.stream.IntStream; /** * Schematic Handler. @@ -39,9 +36,9 @@ public class BukkitSchematicHandler extends SchematicHandler { new CuboidRegion(BukkitUtil.IMP.getWeWorld(world), bot.getBlockVector3(), top.getBlockVector3()); - final int width = top.getX() - bot.getX() + 1; - int height = top.getY() - bot.getY() + 1; - final int length = top.getZ() - bot.getZ() + 1; + final int width = cuboidRegion.getWidth(); + int height = cuboidRegion.getHeight(); + final int length = cuboidRegion.getLength(); Map schematic = new HashMap<>(); schematic.put("Version", new IntTag(1)); @@ -89,109 +86,106 @@ public class BukkitSchematicHandler extends SchematicHandler { RegionWrapper region = queue.poll(); Location pos1 = new Location(world, region.minX, region.minY, region.minZ); Location pos2 = new Location(world, region.maxX, region.maxY, region.maxZ); - final int bx = bot.getX(); - final int bz = bot.getZ(); final int p1x = pos1.getX(); final int p1z = pos1.getZ(); final int p2x = pos2.getX(); final int p2z = pos2.getZ(); - final int bcx = p1x >> 4; - final int bcz = p1z >> 4; - final int tcx = p2x >> 4; - final int tcz = p2z >> 4; final int sy = pos1.getY(); final int ey = pos2.getY(); - // Generate list of chunks - final ArrayList chunks = new ArrayList<>(); - for (int x = bcx; x <= tcx; x++) { - for (int z = bcz; z <= tcz; z++) { - chunks.add(new ChunkLoc(x, z)); - } - } - final World worldObj = Bukkit.getWorld(world); - // Main thread + Iterator yiter = IntStream.range(sy, ey).iterator(); TaskManager.runTask(new Runnable() { @Override public void run() { - long start = System.currentTimeMillis(); - while (!chunks.isEmpty() - && System.currentTimeMillis() - start < 20) { - // save schematics - ChunkLoc chunk = chunks.remove(0); - Chunk bc = worldObj.getChunkAt(chunk.x, chunk.z); - if (!bc.load(false)) { - continue; - } - int X = chunk.x; - int Z = chunk.z; - int xxb = X << 4; - int zzb = Z << 4; - int xxt = xxb + 15; - int zzt = zzb + 15; + final Runnable yTask = this; + long ystart = System.currentTimeMillis(); + while (yiter.hasNext() + && System.currentTimeMillis() - ystart < 20) { + final int fy = yiter.next(); + Iterator ziter = IntStream.range(p1z, p2z).iterator(); + TaskManager.runTask(new Runnable() { + @Override public void run() { + final Runnable zTask = this; + long zstart = System.currentTimeMillis(); + Iterator xiter = + IntStream.range(p1x, p2x).iterator(); + while (ziter.hasNext() + && System.currentTimeMillis() - zstart < 20) { + final int fz = ziter.next(); + TaskManager.runTask(new Runnable() { + @Override public void run() { + long xstart = System.currentTimeMillis(); + while (xiter.hasNext() + && System.currentTimeMillis() - xstart + < 20) { + final int x = xiter.next(); + int rx = x - p1x; + int ry = fy - sy; + int rz = fz - p1z; + BlockVector3 point = + BlockVector3.at(x, fy, fz); + BaseBlock block = + cuboidRegion.getWorld() + .getFullBlock(point); + if (block.getNbtData() != null) { + Map values = + new HashMap<>(); + for (Map.Entry entry : block + .getNbtData().getValue() + .entrySet()) { + values.put(entry.getKey(), + entry.getValue()); + } + // Remove 'id' if it exists. We want 'Id' + values.remove("id"); - if (X == bcx) { - xxb = p1x; - } - if (X == tcx) { - xxt = p2x; - } - if (Z == bcz) { - zzb = p1z; - } - if (Z == tcz) { - zzt = p2z; - } - for (int y = sy; y <= Math.min(255, ey); y++) { - int ry = y - sy; - for (int z = zzb; z <= zzt; z++) { - int rz = z - bz; - for (int x = xxb; x <= xxt; x++) { - int rx = x - bx; - BlockVector3 point = BlockVector3.at(x, y, z); - BaseBlock block = - cuboidRegion.getWorld().getFullBlock(point); - if (block.getNbtData() != null) { - Map values = new HashMap<>(); - for (Map.Entry entry : block - .getNbtData().getValue().entrySet()) { - values - .put(entry.getKey(), entry.getValue()); + // Positions are kept in NBT, we don't want that. + values.remove("x"); + values.remove("y"); + values.remove("z"); + + values.put("Id", new StringTag( + block.getNbtId())); + values.put("Pos", new IntArrayTag( + new int[] {rx, ry, rz})); + + tileEntities + .add(new CompoundTag(values)); + } + String blockKey = + block.toImmutableState() + .getAsString(); + int blockId; + if (palette.containsKey(blockKey)) { + blockId = palette.get(blockKey); + } else { + blockId = palette.size(); + palette + .put(blockKey, palette.size()); + } + + while ((blockId & -128) != 0) { + buffer.write(blockId & 127 | 128); + blockId >>>= 7; + } + buffer.write(blockId); + } + if (xiter.hasNext()) { + TaskManager.runTaskLater(this, 1); + } else { + zTask.run(); + } } - // Remove 'id' if it exists. We want 'Id' - values.remove("id"); - - // Positions are kept in NBT, we don't want that. - values.remove("x"); - values.remove("y"); - values.remove("z"); - - values - .put("Id", new StringTag(block.getNbtId())); - values.put("Pos", - new IntArrayTag(new int[] {rx, ry, rz})); - - tileEntities.add(new CompoundTag(values)); - } - String blockKey = - block.toImmutableState().getAsString(); - int blockId; - if (palette.containsKey(blockKey)) { - blockId = palette.get(blockKey); - } else { - blockId = palette.size(); - palette.put(blockKey, palette.size()); - } - - while ((blockId & -128) != 0) { - buffer.write(blockId & 127 | 128); - blockId >>>= 7; - } - buffer.write(blockId); + }); + } + if (ziter.hasNext()) { + TaskManager.runTaskLater(zTask, 1); + } else { + yTask.run(); } } - } + }); } - if (!chunks.isEmpty()) { - TaskManager.runTaskLater(this, 1); + if (yiter.hasNext()) { + TaskManager.runTaskLater(yTask, 1); } else { regionTask.run(); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java index c0081e14b..a49fb8ae7 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java @@ -77,24 +77,17 @@ public abstract class SchematicHandler { if (value == null) { MainUtil.sendMessage(null, "&7 - Skipped plot &c" + plot.getId()); } else { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - MainUtil.sendMessage(null, "&6ID: " + plot.getId()); - boolean result = SchematicHandler.manager.save(value, - directory + File.separator + name + ".schematic"); - if (!result) { - MainUtil.sendMessage(null, - "&7 - Failed to save &c" + plot.getId()); - } else { - MainUtil - .sendMessage(null, "&7 - &a success: " + plot.getId()); - } - TaskManager.runTask(new Runnable() { - @Override public void run() { - THIS.run(); - } - }); + TaskManager.runTaskAsync(() -> { + MainUtil.sendMessage(null, "&6ID: " + plot.getId()); + boolean result = SchematicHandler.manager + .save(value, directory + File.separator + name + ".schematic"); + if (!result) { + MainUtil + .sendMessage(null, "&7 - Failed to save &c" + plot.getId()); + } else { + MainUtil.sendMessage(null, "&7 - &a success: " + plot.getId()); } + TaskManager.runTask(() -> THIS.run()); }); } } @@ -117,158 +110,156 @@ public abstract class SchematicHandler { final int yOffset, final int zOffset, final boolean autoHeight, final RunnableVal whenDone) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - if (whenDone != null) { - whenDone.value = false; + TaskManager.runTask(() -> { + if (whenDone != null) { + whenDone.value = false; + } + if (schematic == null) { + PlotSquared.debug("Schematic == null :|"); + TaskManager.runTask(whenDone); + return; + } + try { + // Set flags + if (plot.hasOwner()) { + Map flags = schematic.getFlags(); + if (!flags.isEmpty()) { + for (Map.Entry entry : flags.entrySet()) { + plot.setFlag(Flags.getFlag(entry.getKey()), + StringTag.class.cast(entry.getValue()).getValue()); + } + + } } - if (schematic == null) { - PlotSquared.debug("Schematic == null :|"); + final LocalBlockQueue queue = plot.getArea().getQueue(false); + BlockVector3 dimension = schematic.getClipboard().getDimensions(); + final int WIDTH = dimension.getX(); + final int LENGTH = dimension.getZ(); + final int HEIGHT = dimension.getY(); + // Validate dimensions + RegionWrapper region = plot.getLargestRegion(); + if (((region.maxX - region.minX + xOffset + 1) < WIDTH) || ( + (region.maxZ - region.minZ + zOffset + 1) < LENGTH) || (HEIGHT > 256)) { + PlotSquared.debug("Schematic is too large"); + PlotSquared.debug( + "(" + WIDTH + ',' + LENGTH + ',' + HEIGHT + ") is bigger than (" + ( + region.maxX - region.minX) + ',' + (region.maxZ - region.minZ) + + ",256)"); TaskManager.runTask(whenDone); return; } - try { - // Set flags - if (plot.hasOwner()) { - Map flags = schematic.getFlags(); - if (!flags.isEmpty()) { - for (Map.Entry entry : flags.entrySet()) { - plot.setFlag(Flags.getFlag(entry.getKey()), - StringTag.class.cast(entry.getValue()).getValue()); - } - - } - } - final LocalBlockQueue queue = plot.getArea().getQueue(false); - BlockVector3 dimension = schematic.getClipboard().getDimensions(); - final int WIDTH = dimension.getX(); - final int LENGTH = dimension.getZ(); - final int HEIGHT = dimension.getY(); - // Validate dimensions - RegionWrapper region = plot.getLargestRegion(); - if (((region.maxX - region.minX + xOffset + 1) < WIDTH) || ( - (region.maxZ - region.minZ + zOffset + 1) < LENGTH) || (HEIGHT > 256)) { - PlotSquared.debug("Schematic is too large"); - PlotSquared.debug( - "(" + WIDTH + ',' + LENGTH + ',' + HEIGHT + ") is bigger than (" + ( - region.maxX - region.minX) + ',' + (region.maxZ - region.minZ) - + ",256)"); - TaskManager.runTask(whenDone); - return; - } - // block type and data arrays - final BlockArrayClipboard blockArrayClipboard = schematic.getClipboard(); - // Calculate the optimal height to paste the schematic at - final int y_offset_actual; - if (autoHeight) { - if (HEIGHT >= 256) { - y_offset_actual = yOffset; - } else { - PlotArea pw = plot.getArea(); - if (pw instanceof ClassicPlotWorld) { - y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT; - } else { - y_offset_actual = yOffset + 1 + MainUtil - .getHeighestBlock(plot.getWorldName(), region.minX + 1, - region.minZ + 1); - } - } - } else { + // block type and data arrays + final BlockArrayClipboard blockArrayClipboard = schematic.getClipboard(); + // Calculate the optimal height to paste the schematic at + final int y_offset_actual; + if (autoHeight) { + if (HEIGHT >= 256) { y_offset_actual = yOffset; - } - Location pos1 = - new Location(plot.getWorldName(), region.minX + xOffset, y_offset_actual, - region.minZ + zOffset); - Location pos2 = pos1.clone().add(WIDTH - 1, HEIGHT - 1, LENGTH - 1); - final int p1x = pos1.getX(); - final int p1z = pos1.getZ(); - final int p2x = pos2.getX(); - final int p2z = pos2.getZ(); - final int bcx = p1x >> 4; - final int bcz = p1z >> 4; - final int tcx = p2x >> 4; - final int tcz = p2z >> 4; -/* final ArrayList chunks = new ArrayList<>(); - for (int x = bcx; x <= tcx; x++) { - for (int z = bcz; z <= tcz; z++) { - chunks.add(new ChunkLoc(x, z)); + } else { + PlotArea pw = plot.getArea(); + if (pw instanceof ClassicPlotWorld) { + y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT; + } else { + y_offset_actual = yOffset + 1 + MainUtil + .getHeighestBlock(plot.getWorldName(), region.minX + 1, + region.minZ + 1); } - }*/ - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - //int count = 0; - //while (!chunks.isEmpty() && count < 256) { - //count++; - ChunkLoc chunk = new ChunkLoc(value[0], value[1]); - PlotSquared.log(chunk.toString()); - int x = chunk.x; - int z = chunk.z; - int xxb = x << 4; - int zzb = z << 4; - int xxt = xxb + 15; - int zzt = zzb + 15; - if (x == bcx) { - xxb = p1x; - } - if (x == tcx) { - xxt = p2x; - } - if (z == bcz) { - zzb = p1z; - } - if (z == tcz) { - zzt = p2z; - } - // Paste schematic here - - for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { - int yy = y_offset_actual + ry; - if (yy > 255) { - continue; - } - int i1 = ry * WIDTH * LENGTH; - for (int rz = zzb - p1z; rz <= (zzt - p1z); rz++) { - int i2 = (rz * WIDTH) + i1; - for (int rx = xxb - p1x; rx <= (xxt - p1x); rx++) { - int i = i2 + rx; - int xx = p1x + rx; - int zz = p1z + rz; - BaseBlock id = blockArrayClipboard - .getFullBlock(BlockVector3.at(rx, ry, rz)); - queue.setBlock(xx, yy, zz, id); - } - } - } -/* } - if (!chunks.isEmpty()) { - this.run(); - } else { - queue.flush(); - HashMap tiles = schematic.getClipboard().getTiles(); - if (!tiles.isEmpty()) { - TaskManager.IMP.sync(new RunnableVal() { - @Override public void run(Object value) { - for (Map.Entry entry : schematic - .getTiles().entrySet()) { - BlockLoc loc = entry.getKey(); - restoreTile(queue, entry.getValue(), - p1x + xOffset + loc.x, loc.y + y_offset_actual, - p1z + zOffset + loc.z); - } - } - }); - } - }*/ - } - }, null, 10); - if (whenDone != null) { - whenDone.value = true; - whenDone.run(); } - } catch (Exception e) { - e.printStackTrace(); - TaskManager.runTask(whenDone); + } else { + y_offset_actual = yOffset; } + Location pos1 = + new Location(plot.getWorldName(), region.minX + xOffset, y_offset_actual, + region.minZ + zOffset); + Location pos2 = pos1.clone().add(WIDTH - 1, HEIGHT - 1, LENGTH - 1); + final int p1x = pos1.getX(); + final int p1z = pos1.getZ(); + final int p2x = pos2.getX(); + final int p2z = pos2.getZ(); + final int bcx = p1x >> 4; + final int bcz = p1z >> 4; + final int tcx = p2x >> 4; + final int tcz = p2z >> 4; +/* final ArrayList chunks = new ArrayList<>(); + for (int x = bcx; x <= tcx; x++) { + for (int z = bcz; z <= tcz; z++) { + chunks.add(new ChunkLoc(x, z)); + } + }*/ + ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { + @Override public void run(int[] value) { + //int count = 0; + //while (!chunks.isEmpty() && count < 256) { + //count++; + ChunkLoc chunk = new ChunkLoc(value[0], value[1]); + PlotSquared.log(chunk.toString()); + int x = chunk.x; + int z = chunk.z; + int xxb = x << 4; + int zzb = z << 4; + int xxt = xxb + 15; + int zzt = zzb + 15; + if (x == bcx) { + xxb = p1x; + } + if (x == tcx) { + xxt = p2x; + } + if (z == bcz) { + zzb = p1z; + } + if (z == tcz) { + zzt = p2z; + } + // Paste schematic here + + for (int ry = 0; ry < Math.min(256, HEIGHT); ry++) { + int yy = y_offset_actual + ry; + if (yy > 255) { + continue; + } + int i1 = ry * WIDTH * LENGTH; + for (int rz = zzb - p1z; rz <= (zzt - p1z); rz++) { + int i2 = (rz * WIDTH) + i1; + for (int rx = xxb - p1x; rx <= (xxt - p1x); rx++) { + int i = i2 + rx; + int xx = p1x + rx; + int zz = p1z + rz; + BaseBlock id = blockArrayClipboard + .getFullBlock(BlockVector3.at(rx, ry, rz)); + queue.setBlock(xx, yy, zz, id); + } + } + } +/* } + if (!chunks.isEmpty()) { + this.run(); + } else { + queue.flush(); + HashMap tiles = schematic.getClipboard().getTiles(); + if (!tiles.isEmpty()) { + TaskManager.IMP.sync(new RunnableVal() { + @Override public void run(Object value) { + for (Map.Entry entry : schematic + .getTiles().entrySet()) { + BlockLoc loc = entry.getKey(); + restoreTile(queue, entry.getValue(), + p1x + xOffset + loc.x, loc.y + y_offset_actual, + p1z + zOffset + loc.z); + } + } + }); + } + }*/ + } + }, null, 10); + if (whenDone != null) { + whenDone.value = true; + whenDone.run(); + } + } catch (Exception e) { + e.printStackTrace(); + TaskManager.runTask(whenDone); } }); }