diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java index e5335f720..f4747c03b 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAChunk.java @@ -113,7 +113,7 @@ public class MCAChunk implements IChunkSet { section.blocksLength = -1; }); layer.add("Y").withInt((i, y) -> section.layer = y); - layer.add("Palette").withValue((ValueReader>) (index, map) -> { + layer.add("Palette").withElem((ValueReader>) (index, map) -> { String name = (String) map.get("Name"); BlockType type = BlockTypes.get(name); BlockState state = type.getDefaultState(); @@ -137,14 +137,14 @@ public class MCAChunk implements IChunkSet { section.blocksLength = length; }); blockStates.withLong((index, value) -> section.blocks[index] = value); - level.add("TileEntities").withValue((ValueReader>) (index, value) -> { + level.add("TileEntities").withElem((ValueReader>) (index, value) -> { CompoundTag tile = FaweCache.IMP.asTag(value); int x = tile.getInt("x") & 15; int y = tile.getInt("y"); int z = tile.getInt("z") & 15; tiles.put(x, y, z, tile); }); - level.add("Entities").withValue((ValueReader>) (index, value) -> { + level.add("Entities").withElem((ValueReader>) (index, value) -> { CompoundTag entity = FaweCache.IMP.asTag(value); entities.put(entity.getUUID(), entity); }); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/ElemReader.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/ElemReader.java deleted file mode 100644 index 7019cef1d..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/ElemReader.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.boydti.fawe.jnbt.streamer; - -public interface ElemReader extends StreamReader { - void apply(int index, T value); -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java index 58f8cef4f..1c9330b4c 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/streamer/StreamDelegate.java @@ -15,7 +15,7 @@ public class StreamDelegate { private StreamDelegate[] values; private LazyReader lazyReader; - private ElemReader elemReader; + private ValueReader elemReader; private InfoReader infoReader; private ValueReader valueReader; @@ -176,7 +176,7 @@ public class StreamDelegate { return this; } - public StreamDelegate withElem(ElemReader elemReader) { + public StreamDelegate withElem(ValueReader elemReader) { this.elemReader = elemReader; return this; } @@ -204,7 +204,7 @@ public class StreamDelegate { return valueReader; } - public ElemReader getElemReader() { + public ValueReader getElemReader() { return elemReader; } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboardBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboardBuilder.java new file mode 100644 index 000000000..d1d9f2448 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/LinearClipboardBuilder.java @@ -0,0 +1,28 @@ +package com.boydti.fawe.object.clipboard; + +import com.boydti.fawe.object.io.FastByteArrayOutputStream; + +import java.util.function.BiFunction; + +public class LinearClipboardBuilder { + FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream(); + FastByteArrayOutputStream biomesOut = new FastByteArrayOutputStream(); + + public int width, height, length; + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setLength(int length) { + this.length = length; + } + + public LinearClipboard build() { + return null; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ResizableClipboardBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ResizableClipboardBuilder.java index ffa48eb06..50a3e47bd 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ResizableClipboardBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/clipboard/ResizableClipboardBuilder.java @@ -23,7 +23,6 @@ public class ResizableClipboardBuilder extends MemoryOptimizedHistory { private int maxY = Integer.MIN_VALUE; private int maxZ = Integer.MIN_VALUE; - public ResizableClipboardBuilder(World world) { super(world); } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index 414b00635..629ece96a 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -19,7 +19,6 @@ package com.sk89q.jnbt; -import com.boydti.fawe.jnbt.streamer.ElemReader; import com.boydti.fawe.jnbt.streamer.StreamDelegate; import com.boydti.fawe.jnbt.streamer.ValueReader; @@ -27,6 +26,7 @@ import java.io.Closeable; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -247,11 +247,82 @@ public final class NBTInputStream implements Closeable { } return; } + case NBTConstants.TYPE_LIST: { + int childType = is.readByte(); + int length = is.readInt(); + StreamDelegate child; + scope.acceptInfo(length, childType); + ValueReader valueReader = scope.getValueReader(); + if (valueReader != null) { + List tagList = readListRaw(depth, childType, length); + valueReader.apply(0, tagList); + return; + } + valueReader = scope.getElemReader(); + if (valueReader != null) { + for (int i = 0; i < length; ++i) { + valueReader.apply(i, readTagPayloadRaw(childType, depth + 1)); + } + return; + } + child = scope.get0(); + if (child == null) { + for (int i = 0; i < length; ++i) { + readTagPaylodLazy(childType, depth + 1); + } + } else { + for (int i = 0; i < length; ++i) { + readTagPaylodLazy(childType, depth + 1, child); + } + } + return; + } + case NBTConstants.TYPE_COMPOUND: { + // readDataPayload + scope.acceptInfo(-1, NBTConstants.TYPE_BYTE); + ValueReader valueReader = scope.getValueReader(); + if (valueReader != null) { + valueReader.apply(0, this.readTagPayloadRaw(type, depth)); + return; + } + valueReader = scope.getElemReader(); + if (valueReader != null) { + for (int i = 0; ; i++) { + int childType = is.readByte(); + if (childType == NBTConstants.TYPE_END) { + return; + } + String key = readNamedTagName(childType); + Object value = readTagPayloadRaw(childType, depth + 1); + AbstractMap.SimpleEntry entry = new AbstractMap.SimpleEntry<>(key, value); + valueReader.apply(i, entry); + } + } + while(true) { + int childType = is.readByte(); + if (childType == NBTConstants.TYPE_END) { + return; + } + StreamDelegate child = scope.get(is); + if (child == null) { + readTagPaylodLazy(childType, depth + 1); + } else { + readTagPaylodLazy(childType, depth + 1, child); + } + } + } case NBTConstants.TYPE_BYTE_ARRAY: { int length = is.readInt(); scope.acceptInfo(length, NBTConstants.TYPE_BYTE); if (scope.acceptLazy(length, this)) return; ValueReader valueReader = scope.getValueReader(); + if (valueReader != null) { + byte[] arr = new byte[length]; + is.readFully(arr); + valueReader.apply(0, arr); + return; + } + valueReader = scope.getElemReader(); if (valueReader != null) { int i = 0; DataInputStream dis = is; @@ -275,69 +346,16 @@ public final class NBTInputStream implements Closeable { is.skipBytes(length); return; } - case NBTConstants.TYPE_LIST: { - int childType = is.readByte(); - int length = is.readInt(); - StreamDelegate child; - scope.acceptInfo(length, childType); - ValueReader valueReader = scope.getValueReader(); - if (valueReader != null) { - for (int i = 0; i < length; ++i) { - valueReader.apply(i, readTagPayloadRaw(childType, depth + 1)); - } - return; - } - child = scope.get0(); - if (child == null) { - for (int i = 0; i < length; ++i) { - readTagPaylodLazy(childType, depth + 1); - } - } else { - for (int i = 0; i < length; ++i) { - readTagPaylodLazy(childType, depth + 1, child); - } - } - return; - } - case NBTConstants.TYPE_COMPOUND: { - // readDataPayload - depth++; - scope.acceptInfo(-1, NBTConstants.TYPE_BYTE); - ValueReader valueReader = scope.getValueReader(); - if (valueReader != null) { - valueReader.apply(0, this.readDataPayload(type, depth)); - return; - } - ElemReader elem = scope.getElemReader(); - if (elem != null) { - for (int i = 0; ; i++) { - int childType = is.readByte(); - if (childType == NBTConstants.TYPE_END) { - return; - } - is.skipBytes(is.readShort() & 0xFFFF); - Object child = readTagPayloadRaw(childType, depth); - elem.apply(i, child); - } - } - while(true) { - int childType = is.readByte(); - if (childType == NBTConstants.TYPE_END) { - return; - } - StreamDelegate child = scope.get(is); - if (child == null) { - readTagPaylodLazy(childType, depth + 1); - } else { - readTagPaylodLazy(childType, depth + 1, child); - } - } - } case NBTConstants.TYPE_INT_ARRAY: { int length = is.readInt(); scope.acceptInfo(length, NBTConstants.TYPE_INT); if (scope.acceptLazy(length, this)) return; ValueReader valueReader = scope.getValueReader(); + if (valueReader != null) { + valueReader.apply(0, readIntArrayRaw(length)); + return; + } + valueReader = scope.getElemReader(); if (valueReader != null) { for (int i = 0; i < length; i++) { valueReader.applyInt(i, is.readInt()); @@ -352,6 +370,11 @@ public final class NBTInputStream implements Closeable { scope.acceptInfo(length, NBTConstants.TYPE_LONG); if (scope.acceptLazy(length, this)) return; ValueReader valueReader = scope.getValueReader(); + if (valueReader != null) { + valueReader.apply(0, readLongArrayRaw(length)); + return; + } + valueReader = scope.getElemReader(); if (valueReader != null) { for (int i = 0; i < length; i++) { valueReader.applyLong(i, is.readLong()); @@ -367,6 +390,18 @@ public final class NBTInputStream implements Closeable { } } + private List readListRaw(int depth, int childType, int length) throws IOException { + List tagList = new ArrayList<>(length); + for (int i = 0; i < length; ++i) { + Object tag = readTagPayloadRaw(childType, depth + 1); + if (tag == null) { + throw new IOException("TAG_End not permitted in a list."); + } + tagList.add(tag); + } + return tagList; + } + public static int getSize(int type) { switch (type) { default: @@ -424,15 +459,7 @@ public final class NBTInputStream implements Closeable { case NBTConstants.TYPE_LIST: { int childType = is.readByte(); length = is.readInt(); - List tagList = new ArrayList<>(length); - for (int i = 0; i < length; ++i) { - Object tag = readTagPayloadRaw(childType, depth + 1); - if (tag == null) { - throw new IOException("TAG_End not permitted in a list."); - } - tagList.add(tag); - } - return (tagList); + return readListRaw(depth, childType, length); } case NBTConstants.TYPE_COMPOUND: { Map tagMap = new HashMap<>(); @@ -448,43 +475,51 @@ public final class NBTInputStream implements Closeable { } case NBTConstants.TYPE_INT_ARRAY: { length = is.readInt(); - int[] data = new int[length]; - if (buf == null) { - buf = new byte[1024]; - } - int index = 0; - while (length > 0) { - int toRead = Math.min(length << 2, buf.length); - is.readFully(buf, 0, toRead); - for (int i = 0; i < toRead; i += 4, index++) { - data[index] = ((buf[i] & 0xFF) << 24) + ((buf[i + 1] & 0xFF) << 16) + ((buf[i + 2] & 0xFF) << 8) + (buf[i + 3] & 0xFF); - } - length -= toRead; - } - return (data); + return readIntArrayRaw(length); } case NBTConstants.TYPE_LONG_ARRAY: { length = is.readInt(); - long[] data = new long[length]; - if (buf == null) { - buf = new byte[1024]; - } - int index = 0; - while (length > 0) { - int toRead = Math.min(length << 3, buf.length); - is.readFully(buf, 0, toRead); - for (int i = 0; i < toRead; i += 8, index++) { - data[index] = (((long) buf[i] << 56) | ((long) (buf[i + 1] & 255) << 48) | ((long) (buf[i + 2] & 255) << 40) | ((long) (buf[i + 3] & 255) << 32) | ((long) (buf[i + 4] & 255) << 24) | ((buf[i + 5] & 255) << 16) | ((buf[i + 6] & 255) << 8) | (buf[i + 7] & 255)); - } - length -= toRead; - } - return (data); + return readLongArrayRaw(length); } default: throw new IOException("Invalid tag type: " + type + "."); } } + private int[] readIntArrayRaw(int length) throws IOException { + int[] data = new int[length]; + if (buf == null) { + buf = new byte[1024]; + } + int index = 0; + while (length > 0) { + int toRead = Math.min(length << 2, buf.length); + is.readFully(buf, 0, toRead); + for (int i = 0; i < toRead; i += 4, index++) { + data[index] = ((buf[i] & 0xFF) << 24) + ((buf[i + 1] & 0xFF) << 16) + ((buf[i + 2] & 0xFF) << 8) + (buf[i + 3] & 0xFF); + } + length -= toRead; + } + return data; + } + + private long[] readLongArrayRaw(int length) throws IOException { + long[] data = new long[length]; + if (buf == null) { + buf = new byte[1024]; + } + int index = 0; + while (length > 0) { + int toRead = Math.min(length << 3, buf.length); + is.readFully(buf, 0, toRead); + for (int i = 0; i < toRead; i += 8, index++) { + data[index] = (((long) buf[i] << 56) | ((long) (buf[i + 1] & 255) << 48) | ((long) (buf[i + 2] & 255) << 40) | ((long) (buf[i + 3] & 255) << 32) | ((long) (buf[i + 4] & 255) << 24) | ((buf[i + 5] & 255) << 16) | ((buf[i + 6] & 255) << 8) | (buf[i + 7] & 255)); + } + length -= toRead; + } + return (data); + } + /** * Reads the payload of a tag given the type. * @@ -548,7 +583,6 @@ public final class NBTInputStream implements Closeable { tagMap.put(namedTag.getName(), tag); } } - return new CompoundTag(tagMap); case NBTConstants.TYPE_INT_ARRAY: length = is.readInt(); @@ -569,84 +603,6 @@ public final class NBTInputStream implements Closeable { } } - /* - Don't delete please - */ - public Object readDataPayload(int type, int depth) throws IOException { - switch (type) { - case NBTConstants.TYPE_END: - if (depth == 0) { - throw new IOException( - "TAG_End found without a TAG_Compound/TAG_List tag preceding it."); - } else { - return null; - } - case NBTConstants.TYPE_BYTE: - return is.readByte(); - case NBTConstants.TYPE_SHORT: - return is.readShort(); - case NBTConstants.TYPE_INT: - return is.readInt(); - case NBTConstants.TYPE_LONG: - return is.readLong(); - case NBTConstants.TYPE_FLOAT: - return is.readFloat(); - case NBTConstants.TYPE_DOUBLE: - return is.readDouble(); - case NBTConstants.TYPE_BYTE_ARRAY: - int length = is.readInt(); - byte[] bytes = new byte[length]; - is.readFully(bytes); - return bytes; - case NBTConstants.TYPE_STRING: - length = is.readShort(); - bytes = new byte[length]; - is.readFully(bytes); - return new String(bytes, NBTConstants.CHARSET); - case NBTConstants.TYPE_LIST: - int childType = is.readByte(); - length = is.readInt(); - ArrayList list = new ArrayList<>(); - for (int i = 0; i < length; ++i) { - Object obj = readDataPayload(childType, depth + 1); - if (obj == null) { - throw new IOException("TAG_End not permitted in a list."); - } - list.add(obj); - } - return list; - case NBTConstants.TYPE_COMPOUND: - Map map = new HashMap<>(); - while (true) { - int newType = is.readByte(); - if (newType == NBTConstants.TYPE_END) { - return map; - } - String name = readNamedTagName(newType); - Object data = readDataPayload(newType, depth + 1); - map.put(name, data); - } - case NBTConstants.TYPE_INT_ARRAY: { - length = is.readInt(); - int[] data = new int[length]; - for (int i = 0; i < length; i++) { - data[i] = is.readInt(); - } - return data; - } - case NBTConstants.TYPE_LONG_ARRAY: { - length = is.readInt(); - long[] data = new long[length]; - for (int i = 0; i < length; i++) { - data[i] = is.readLong(); - } - return data; - } - default: - throw new IOException("Invalid tag type: " + type + "."); - } - } - @Override public void close() throws IOException { is.close(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java index 2dce70ba4..36ad577b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -19,32 +19,51 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.Settings; +import com.boydti.fawe.jnbt.streamer.InfoReader; +import com.boydti.fawe.jnbt.streamer.IntValueReader; import com.boydti.fawe.jnbt.streamer.StreamDelegate; import com.boydti.fawe.jnbt.streamer.ValueReader; +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.clipboard.CPUOptimizedClipboard; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.object.clipboard.LinearClipboard; import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard; import com.boydti.fawe.object.io.FastByteArrayOutputStream; +import com.boydti.fawe.object.io.FastByteArraysInputStream; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; @@ -72,42 +91,10 @@ public class SpongeSchematicReader extends NBTSchematicReader { this.inputStream = inputStream; } - @Override - public Clipboard read() throws IOException { - return read(UUID.randomUUID()); - } - - @Override - public Clipboard read(UUID uuid) throws IOException { - return reader(uuid); - } - - @Override - public Clipboard read(UUID uuid, Function createOutput) { - return null; - } - private int width, height, length; private int offsetX, offsetY, offsetZ; - private char[] palette; + private char[] palette, biomePalette; private BlockVector3 min; - private LinearClipboard fc; - - private LinearClipboard setupClipboard(int size, UUID uuid) { - if (fc != null) { - if (fc.getDimensions().getX() == 0) { -// fc.setDimensions(BlockVector3.at(size, 1, 1)); - } - return fc; - } - if (Settings.IMP.CLIPBOARD.USE_DISK) { - return fc = new DiskOptimizedClipboard(BlockVector3.at(size, 1, 1), uuid); - } else if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL == 0) { - return fc = new CPUOptimizedClipboard(BlockVector3.at(size, 1, 1)); - } else { - return fc = new MemoryOptimizedClipboard(BlockVector3.at(size, 1, 1)); - } - } private String fix(String palettePart) { if (fixer == null || dataVersion == -1) return palettePart; @@ -124,13 +111,16 @@ public class SpongeSchematicReader extends NBTSchematicReader { return fixer.fixUp(DataFixer.FixTypes.ENTITY, tag, dataVersion); } - private Clipboard reader(UUID uuid) throws IOException { - width = height = length = offsetX = offsetY = offsetZ = Integer.MIN_VALUE; + private FastByteArrayOutputStream blocksOut; + private FaweOutputStream blocks; - final BlockArrayClipboard clipboard = new BlockArrayClipboard(new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(0, 0, 0)), fc); - FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream(); - FastByteArrayOutputStream biomesOut = new FastByteArrayOutputStream(); + private FastByteArrayOutputStream biomesOut; + private FaweOutputStream biomes; + private List> tiles; + private List> entities; + + public StreamDelegate createDelegate() { StreamDelegate root = new StreamDelegate(); StreamDelegate schematic = root.add("Schematic"); schematic.add("DataVersion").withInt((i, v) -> dataVersion = v); @@ -147,135 +137,199 @@ public class SpongeSchematicReader extends NBTSchematicReader { StreamDelegate paletteDelegate = schematic.add("Palette"); paletteDelegate.withValue(new ValueReader>() { @Override - public void apply(int index, Map value) { - + public void apply(int ignore, Map v) { + palette = new char[v.size()]; + for (Map.Entry entry : v.entrySet()) { + BlockState state = null; + try { + String palettePart = entry.getKey(); + palettePart = fix(entry.getKey()); + state = BlockState.get(palettePart); + } catch (InputParseException e) { + e.printStackTrace(); + } + int index = (int) entry.getValue(); + palette[index] = (char) state.getOrdinal(); + } + } + }); + StreamDelegate blockData = schematic.add("BlockData"); + blockData.withInfo((length, type) -> { + blocksOut = new FastByteArrayOutputStream(); + blocks = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut)); + }); + blockData.withInt(new IntValueReader() { + @Override + public void applyInt(int index, int value) { + try { + blocks.writeVarInt(value); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + StreamDelegate tilesDelegate = schematic.add("TileEntities"); + tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length)); + tilesDelegate.withElem(new ValueReader>() { + @Override + public void apply(int index, Map tile) { + tiles.add(tile); } }); -// schematic.add("Palette", (BiConsumer>) (i, v) -> { -// palette = new char[v.size()]; -// for (Map.Entry entry : v.entrySet()) { -// BlockState state = null; -// try { -// String palettePart = fix(entry.getKey()); -// state = BlockState.get(palettePart); -// } catch (InputParseException e) { -// e.printStackTrace(); -// } -// int index = ((IntTag) entry.getValue()).getValue(); -// palette[index] = (char) state.getOrdinal(); -// } -// }); -// -// /// readBiomes -// -// streamer.addReader("Schematic.BlockData", NBTStreamer.ReadType.ELEM, (NBTStreamer.LazyReader) (arrayLen, dis) -> { -// try (FaweOutputStream blocks = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut))) { -// IOUtil.copy(dis, blocks, arrayLen); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// }); -// streamer.addReader("Schematic.BlockData", NBTStreamer.ReadType.ELEM, (NBTStreamer.LazyReader) (arrayLen, dis) -> { -// try (FaweOutputStream biomes = new FaweOutputStream(new LZ4BlockOutputStream(biomesOut))) { -// IOUtil.copy(dis, biomes, arrayLen); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// }); -// streamer.addReader("Schematic.TileEntities", NBTStreamer.ReadType.ELEM,(BiConsumer) (index, value) -> { -// if (fc == null) { -// setupClipboard(0, uuid); -// } -// int[] pos = value.getIntArray("Pos"); -// int x,y,z; -// if (pos.length != 3) { -// System.out.println("Invalid tile " + value); -// if (!value.containsKey("x") || !value.containsKey("y") || !value.containsKey("z")) { -// return; -// } -// x = value.getInt("x"); -// y = value.getInt("y"); -// z = value.getInt("z"); -// } else { -// x = pos[0]; -// y = pos[1]; -// z = pos[2]; -// } -// Map values = value.getValue(); -// Tag id = values.get("Id"); -// if (id != null) { -// values.put("x", new IntTag(x)); -// values.put("y", new IntTag(y)); -// values.put("z", new IntTag(z)); -// values.put("id", id); -// } -// values.remove("Id"); -// values.remove("Pos"); -// value = fixBlockEntity(value); -// fc.setTile(x, y, z, value); -// }); -// streamer.addReader("Schematic.Entities", NBTStreamer.ReadType.ELEM,(BiConsumer) (index, compound) -> { -// if (fc == null) { -// setupClipboard(0, uuid); -// } -// Map value = compound.getValue(); -// StringTag id = (StringTag) value.get("Id"); -// if (id == null) { -// id = (StringTag) value.get("id"); -// if (id == null) { -// return; -// } -// } else { -// value.put("id", id); -// value.remove("Id"); -// } -// -// EntityType type = EntityTypes.parse(id.getValue()); -// if (type != null) { -// compound = fixEntity(compound); -// BaseEntity state = new BaseEntity(type, compound); -// Location loc = compound.getEntityLocation(fc); -// fc.createEntity(loc, state); -// } else { -// Fawe.debug("Invalid entity: " + id); -// } -// }); -// streamer.readFully(); -// if (fc == null) setupClipboard(length * width * height, uuid); -//// fc.setDimensions(BlockVector3.at(width, height, length)); -// BlockVector3 origin = min; -// CuboidRegion region; -// if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) { -// origin = origin.subtract(BlockVector3.at(offsetX, offsetY, offsetZ)); -// } -// region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); -// if (blocksOut.getSize() != 0) { -// try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(blocksOut.toByteArrays())))) { -// int volume = width * height * length; -// if (palette.length < 128) { -// for (int index = 0; index < volume; index++) { -// BlockState state = BlockTypes.states[palette[fis.read()]]; -// fc.setBlock(index, state); -// } -// } else { -// for (int index = 0; index < volume; index++) { -// BlockState state = BlockTypes.states[palette[fis.readVarInt()]]; -// fc.setBlock(index, state); -// } -// } -// } -// } -// if (biomesOut.getSize() != 0) { -// try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) { -// int volume = width * length; -// for (int index = 0; index < volume; index++) { -// fc.setBiome(index, BiomeTypes.get(fis.read())); -// } -// } -// } -//// clipboard.init(region, fc); -// clipboard.setOrigin(origin); + StreamDelegate entitiesDelegate = schematic.add("Entities"); + entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length)); + entitiesDelegate.withElem(new ValueReader>() { + @Override + public void apply(int index, Map entity) { + entities.add(entity); + } + }); + StreamDelegate biomeData = schematic.add("BiomeData"); + biomeData.withInfo(new InfoReader() { + @Override + public void apply(int length, int type) { + biomesOut = new FastByteArrayOutputStream(); + biomes = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut)); + } + }); + biomeData.withElem(new IntValueReader() { + @Override + public void applyInt(int index, int value) { + try { + biomes.write(value); // byte of varInt + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + StreamDelegate biomePaletteDelegate = schematic.add("BiomePalette"); + biomePaletteDelegate.withInfo(new InfoReader() { + @Override + public void apply(int length, int type) { + biomePalette = new char[length]; + } + }); + biomePaletteDelegate.withElem(new ValueReader>() { + @Override + public void apply(int index, Map.Entry palettePart) { + String key = palettePart.getKey(); + if (fixer != null) { + key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion); + } + BiomeType biome = BiomeTypes.get(key); + if (biome == null) { + System.out.println("Unknown biome " + key); + biome = BiomeTypes.FOREST; + } + int paletteIndex = palettePart.getValue().intValue(); + biomePalette[paletteIndex] = (char) biome.getInternalId(); + } + }); + return root; + } + @Override + public Clipboard read(UUID uuid, Function createOutput) throws IOException { + StreamDelegate root = createDelegate(); + inputStream.readNamedTagLazy(root); + BlockVector3 dimensions = BlockVector3.at(width, height, length); + Clipboard clipboard = createOutput.apply(dimensions); + + BlockVector3 origin = min; + CuboidRegion region; + if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) { + origin = origin.subtract(BlockVector3.at(offsetX, offsetY, offsetZ)); + } + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + if (blocksOut.getSize() != 0) { + try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(blocksOut.toByteArrays())))) { + int volume = width * height * length; + if (palette.length < 128) { + for (int index = 0; index < volume; index++) { + BlockState state = BlockTypes.states[palette[fis.read()]]; + clipboard.setBlock(index, state); + } + } else { + for (int index = 0; index < volume; index++) { + BlockState state = BlockTypes.states[palette[fis.readVarInt()]]; + clipboard.setBlock(index, state); + } + } + } + } + if (biomesOut.getSize() != 0) { + try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) { + int volume = width * length; + for (int index = 0; index < volume; index++) { + clipboard.setBiome(index, BiomeTypes.get(fis.read())); + } + } + } + // tiles + if (tiles != null && !tiles.isEmpty()) { + for (Map tileRaw : tiles) { + CompoundTag tile = FaweCache.IMP.asTag(tileRaw); + + int[] pos = tile.getIntArray("Pos"); + int x,y,z; + if (pos.length != 3) { + System.out.println("Invalid tile " + tile); + if (!tile.containsKey("x") || !tile.containsKey("y") || !tile.containsKey("z")) { + return null; + } + x = tile.getInt("x"); + y = tile.getInt("y"); + z = tile.getInt("z"); + } else { + x = pos[0]; + y = pos[1]; + z = pos[2]; + } + Map values = tile.getValue(); + Tag id = values.get("Id"); + if (id != null) { + values.put("x", new IntTag(x)); + values.put("y", new IntTag(y)); + values.put("z", new IntTag(z)); + values.put("id", id); + } + values.remove("Id"); + values.remove("Pos"); + + tile = fixBlockEntity(tile); + clipboard.setTile(x, y, z, tile); + } + } + + // entities + if (entities != null && !entities.isEmpty()) { + for (Map entRaw : entities) { + CompoundTag ent = FaweCache.IMP.asTag(entRaw); + + Map value = ent.getValue(); + StringTag id = (StringTag) value.get("Id"); + if (id == null) { + id = (StringTag) value.get("id"); + if (id == null) { + return null; + } + } + value.put("id", id); + value.remove("Id"); + + EntityType type = EntityTypes.parse(id.getValue()); + if (type != null) { + ent = fixEntity(ent); + BaseEntity state = new BaseEntity(type, ent); + Location loc = ent.getEntityLocation(clipboard); + clipboard.createEntity(loc, state); + } else { + Fawe.debug("Invalid entity: " + id); + } + } + } + + clipboard.setOrigin(origin); return clipboard; }