Search in sources :

Example 1 with IntArrayTag

use of com.sk89q.jnbt.IntArrayTag in project FastAsyncWorldEdit by IntellectualSites.

the class FastSchematicWriter method write2.

/**
 * Writes a version 2 schematic file.
 *
 * @param clipboard The clipboard
 */
private void write2(Clipboard clipboard) throws IOException {
    Region region = clipboard.getRegion();
    BlockVector3 origin = clipboard.getOrigin();
    BlockVector3 min = region.getMinimumPoint();
    BlockVector3 offset = min.subtract(origin);
    int width = region.getWidth();
    int height = region.getHeight();
    int length = region.getLength();
    if (width > MAX_SIZE) {
        throw new IllegalArgumentException("Width of region too large for a .schematic");
    }
    if (height > MAX_SIZE) {
        throw new IllegalArgumentException("Height of region too large for a .schematic");
    }
    if (length > MAX_SIZE) {
        throw new IllegalArgumentException("Length of region too large for a .schematic");
    }
    final DataOutput rawStream = outputStream.getOutputStream();
    outputStream.writeLazyCompoundTag("Schematic", out -> {
        out.writeNamedTag("DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion());
        out.writeNamedTag("Version", CURRENT_VERSION);
        out.writeNamedTag("Width", (short) width);
        out.writeNamedTag("Height", (short) height);
        out.writeNamedTag("Length", (short) length);
        // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
        out.writeNamedTag("Offset", new int[] { min.getBlockX(), min.getBlockY(), min.getBlockZ() });
        out.writeLazyCompoundTag("Metadata", out1 -> {
            out1.writeNamedTag("WEOffsetX", offset.getBlockX());
            out1.writeNamedTag("WEOffsetY", offset.getBlockY());
            out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
            out1.writeNamedTag("FAWEVersion", Fawe.instance().getVersion().build);
        });
        ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream();
        FaweOutputStream blocksOut = new FaweOutputStream(new DataOutputStream(new LZ4BlockOutputStream(blocksCompressed)));
        ByteArrayOutputStream tilesCompressed = new ByteArrayOutputStream();
        NBTOutputStream tilesOut = new NBTOutputStream(new LZ4BlockOutputStream(tilesCompressed));
        List<Integer> paletteList = new ArrayList<>();
        char[] palette = new char[BlockTypesCache.states.length];
        Arrays.fill(palette, Character.MAX_VALUE);
        int paletteMax = 0;
        int numTiles = 0;
        Clipboard finalClipboard;
        if (clipboard instanceof BlockArrayClipboard) {
            finalClipboard = ((BlockArrayClipboard) clipboard).getParent();
        } else {
            finalClipboard = clipboard;
        }
        Iterator<BlockVector3> iterator = finalClipboard.iterator(Order.YZX);
        while (iterator.hasNext()) {
            BlockVector3 pos = iterator.next();
            BaseBlock block = pos.getFullBlock(finalClipboard);
            CompoundTag nbt = block.getNbtData();
            if (nbt != null) {
                Map<String, Tag> values = new HashMap<>(nbt.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()));
                // Remove 'id' if it exists. We want 'Id'.
                // Do this after we get "getNbtId" cos otherwise "getNbtId" doesn't work.
                // Dum.
                values.remove("id");
                values.put("Pos", new IntArrayTag(new int[] { pos.getX(), pos.getY(), pos.getZ() }));
                numTiles++;
                tilesOut.writeTagPayload(new CompoundTag(values));
            }
            int ordinal = block.getOrdinal();
            if (ordinal == 0) {
                ordinal = 1;
            }
            char value = palette[ordinal];
            if (value == Character.MAX_VALUE) {
                int size = paletteMax++;
                palette[ordinal] = value = (char) size;
                paletteList.add(ordinal);
            }
            blocksOut.writeVarInt(value);
        }
        // close
        tilesOut.close();
        blocksOut.close();
        out.writeNamedTag("PaletteMax", paletteMax);
        out.writeLazyCompoundTag("Palette", out12 -> {
            for (int i = 0; i < paletteList.size(); i++) {
                int stateOrdinal = paletteList.get(i);
                BlockState state = BlockTypesCache.states[stateOrdinal];
                out12.writeNamedTag(state.getAsString(), i);
            }
        });
        out.writeNamedTagName("BlockData", NBTConstants.TYPE_BYTE_ARRAY);
        rawStream.writeInt(blocksOut.size());
        try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(blocksCompressed.toByteArray()))) {
            IOUtil.copy(in, rawStream);
        }
        if (numTiles != 0) {
            out.writeNamedTagName("BlockEntities", NBTConstants.TYPE_LIST);
            rawStream.write(NBTConstants.TYPE_COMPOUND);
            rawStream.writeInt(numTiles);
            try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(tilesCompressed.toByteArray()))) {
                IOUtil.copy(in, rawStream);
            }
        } else {
            out.writeNamedEmptyList("BlockEntities");
        }
        if (finalClipboard.hasBiomes()) {
            writeBiomes(finalClipboard, out);
        }
        List<Tag> entities = new ArrayList<>();
        for (Entity entity : finalClipboard.getEntities()) {
            BaseEntity state = entity.getState();
            if (state != null) {
                Map<String, Tag> values = new HashMap<>();
                // Put NBT provided data
                CompoundTag rawTag = state.getNbtData();
                if (rawTag != null) {
                    values.putAll(rawTag.getValue());
                }
                // Store our location data, overwriting any
                values.remove("id");
                Location loc = entity.getLocation();
                if (!brokenEntities) {
                    loc = loc.setPosition(loc.add(min.toVector3()));
                }
                values.put("Id", new StringTag(state.getType().getId()));
                values.put("Pos", writeVector(loc));
                values.put("Rotation", writeRotation(entity.getLocation()));
                CompoundTag entityTag = new CompoundTag(values);
                entities.add(entityTag);
            }
        }
        if (entities.isEmpty()) {
            out.writeNamedEmptyList("Entities");
        } else {
            out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
        }
    });
}
Also used : StringTag(com.sk89q.jnbt.StringTag) DataOutput(java.io.DataOutput) BaseEntity(com.sk89q.worldedit.entity.BaseEntity) Entity(com.sk89q.worldedit.entity.Entity) HashMap(java.util.HashMap) DataOutputStream(java.io.DataOutputStream) ArrayList(java.util.ArrayList) BaseBlock(com.sk89q.worldedit.world.block.BaseBlock) LZ4BlockOutputStream(net.jpountz.lz4.LZ4BlockOutputStream) CompoundTag(com.sk89q.jnbt.CompoundTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) BaseEntity(com.sk89q.worldedit.entity.BaseEntity) ByteArrayOutputStream(java.io.ByteArrayOutputStream) BlockVector3(com.sk89q.worldedit.math.BlockVector3) MutableBlockVector3(com.fastasyncworldedit.core.math.MutableBlockVector3) NBTOutputStream(com.sk89q.jnbt.NBTOutputStream) LZ4BlockInputStream(net.jpountz.lz4.LZ4BlockInputStream) ListTag(com.sk89q.jnbt.ListTag) BlockState(com.sk89q.worldedit.world.block.BlockState) ByteArrayInputStream(java.io.ByteArrayInputStream) Region(com.sk89q.worldedit.regions.Region) Clipboard(com.sk89q.worldedit.extent.clipboard.Clipboard) BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) StringTag(com.sk89q.jnbt.StringTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) ListTag(com.sk89q.jnbt.ListTag) CompoundTag(com.sk89q.jnbt.CompoundTag) Tag(com.sk89q.jnbt.Tag) FaweOutputStream(com.fastasyncworldedit.core.internal.io.FaweOutputStream) Location(com.sk89q.worldedit.util.Location)

Example 2 with IntArrayTag

use of com.sk89q.jnbt.IntArrayTag in project FastAsyncWorldEdit by IntellectualSites.

the class SpongeSchematicReader method readVersion1.

private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
    BlockVector3 origin;
    Region region;
    Map<String, Tag> schematic = schematicTag.getValue();
    int width = requireTag(schematic, "Width", ShortTag.class).getValue();
    int height = requireTag(schematic, "Height", ShortTag.class).getValue();
    int length = requireTag(schematic, "Length", ShortTag.class).getValue();
    IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class);
    int[] offsetParts;
    if (offsetTag != null) {
        offsetParts = offsetTag.getValue();
        if (offsetParts.length != 3) {
            throw new IOException("Invalid offset specified in schematic.");
        }
    } else {
        offsetParts = new int[] { 0, 0, 0 };
    }
    BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]);
    CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class);
    if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) {
        // We appear to have WorldEdit Metadata
        Map<String, Tag> metadata = metadataTag.getValue();
        int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue();
        int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue();
        int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue();
        BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
        origin = min.subtract(offset);
        region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
    } else {
        origin = min;
        region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
    }
    IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class);
    Map<String, Tag> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue();
    if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) {
        throw new IOException("Block palette size does not match expected size.");
    }
    Map<Integer, BlockState> palette = new HashMap<>();
    ParserContext parserContext = new ParserContext();
    parserContext.setRestricted(false);
    parserContext.setTryLegacy(false);
    parserContext.setPreferringWildcard(false);
    for (String palettePart : paletteObject.keySet()) {
        int id = requireTag(paletteObject, palettePart, IntTag.class).getValue();
        if (fixer != null) {
            palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
        }
        BlockState state;
        try {
            state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState();
        } catch (InputParseException e) {
            LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air.");
            state = BlockTypes.AIR.getDefaultState();
        }
        palette.put(id, state);
    }
    byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue();
    Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
    ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class);
    if (tileEntities == null) {
        tileEntities = getTag(schematic, "TileEntities", ListTag.class);
    }
    if (tileEntities != null) {
        List<Map<String, Tag>> tileEntityTags = tileEntities.getValue().stream().map(tag -> (CompoundTag) tag).map(CompoundTag::getValue).collect(Collectors.toList());
        for (Map<String, Tag> tileEntity : tileEntityTags) {
            int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
            final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]);
            Map<String, Tag> values = Maps.newHashMap(tileEntity);
            values.put("x", new IntTag(pt.getBlockX()));
            values.put("y", new IntTag(pt.getBlockY()));
            values.put("z", new IntTag(pt.getBlockZ()));
            // FAWE start - support old, corrupt schematics
            Tag id = values.get("Id");
            if (id == null) {
                id = values.get("id");
            }
            if (id == null) {
                continue;
            }
            // FAWE end
            values.put("id", values.get("Id"));
            values.remove("Id");
            values.remove("Pos");
            if (fixer != null) {
                // FAWE start - BinaryTag
                tileEntity = ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values).asBinaryTag(), dataVersion))).getValue();
            // FAWE end
            } else {
                tileEntity = values;
            }
            tileEntitiesMap.put(pt, tileEntity);
        }
    }
    BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
    clipboard.setOrigin(origin);
    int index = 0;
    int i = 0;
    int value;
    int varintLength;
    while (i < blocks.length) {
        value = 0;
        varintLength = 0;
        while (true) {
            value |= (blocks[i] & 127) << (varintLength++ * 7);
            if (varintLength > 5) {
                throw new IOException("VarInt too big (probably corrupted data)");
            }
            if ((blocks[i] & 128) != 128) {
                i++;
                break;
            }
            i++;
        }
        // index = (y * length * width) + (z * width) + x
        int y = index / (width * length);
        int z = (index % (width * length)) / width;
        int x = (index % (width * length)) % width;
        BlockState state = palette.get(value);
        BlockVector3 pt = BlockVector3.at(x, y, z);
        try {
            if (tileEntitiesMap.containsKey(pt)) {
                clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt))));
            } else {
                clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state);
            }
        } catch (WorldEditException e) {
            throw new IOException("Failed to load a block in the schematic");
        }
        index++;
    }
    return clipboard;
}
Also used : HashMap(java.util.HashMap) CuboidRegion(com.sk89q.worldedit.regions.CuboidRegion) InputParseException(com.sk89q.worldedit.extension.input.InputParseException) CompoundTag(com.sk89q.jnbt.CompoundTag) IntTag(com.sk89q.jnbt.IntTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) IOException(java.io.IOException) BlockVector3(com.sk89q.worldedit.math.BlockVector3) ListTag(com.sk89q.jnbt.ListTag) ShortTag(com.sk89q.jnbt.ShortTag) BlockState(com.sk89q.worldedit.world.block.BlockState) CuboidRegion(com.sk89q.worldedit.regions.CuboidRegion) Region(com.sk89q.worldedit.regions.Region) StringTag(com.sk89q.jnbt.StringTag) ShortTag(com.sk89q.jnbt.ShortTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) ListTag(com.sk89q.jnbt.ListTag) IntTag(com.sk89q.jnbt.IntTag) NamedTag(com.sk89q.jnbt.NamedTag) ByteArrayTag(com.sk89q.jnbt.ByteArrayTag) CompoundTag(com.sk89q.jnbt.CompoundTag) Tag(com.sk89q.jnbt.Tag) ParserContext(com.sk89q.worldedit.extension.input.ParserContext) WorldEditException(com.sk89q.worldedit.WorldEditException) HashMap(java.util.HashMap) Map(java.util.Map) ByteArrayTag(com.sk89q.jnbt.ByteArrayTag)

Example 3 with IntArrayTag

use of com.sk89q.jnbt.IntArrayTag in project FastAsyncWorldEdit by IntellectualSites.

the class SpongeSchematicWriter method write2.

/**
 * Writes a version 2 schematic file.
 *
 * @param clipboard The clipboard
 * @return The schematic map
 */
private Map<String, Tag> write2(Clipboard clipboard) {
    Region region = clipboard.getRegion();
    BlockVector3 origin = clipboard.getOrigin();
    BlockVector3 min = region.getMinimumPoint();
    BlockVector3 offset = min.subtract(origin);
    int width = region.getWidth();
    int height = region.getHeight();
    int length = region.getLength();
    if (width > MAX_SIZE) {
        throw new IllegalArgumentException("Width of region too large for a .schematic");
    }
    if (height > MAX_SIZE) {
        throw new IllegalArgumentException("Height of region too large for a .schematic");
    }
    if (length > MAX_SIZE) {
        throw new IllegalArgumentException("Length of region too large for a .schematic");
    }
    Map<String, Tag> schematic = new HashMap<>();
    schematic.put("Version", new IntTag(CURRENT_VERSION));
    schematic.put("DataVersion", new IntTag(WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
    Map<String, Tag> metadata = new HashMap<>();
    metadata.put("WEOffsetX", new IntTag(offset.getBlockX()));
    metadata.put("WEOffsetY", new IntTag(offset.getBlockY()));
    metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ()));
    metadata.put("FAWEVersion", new IntTag(Fawe.instance().getVersion().build));
    schematic.put("Metadata", new CompoundTag(metadata));
    schematic.put("Width", new ShortTag((short) width));
    schematic.put("Height", new ShortTag((short) height));
    schematic.put("Length", new ShortTag((short) length));
    // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
    schematic.put("Offset", new IntArrayTag(new int[] { min.getBlockX(), min.getBlockY(), min.getBlockZ() }));
    int paletteMax = 0;
    Map<String, Integer> palette = new HashMap<>();
    List<CompoundTag> tileEntities = new ArrayList<>();
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length);
    for (int y = 0; y < height; y++) {
        int y0 = min.getBlockY() + y;
        for (int z = 0; z < length; z++) {
            int z0 = min.getBlockZ() + z;
            for (int x = 0; x < width; x++) {
                int x0 = min.getBlockX() + x;
                BlockVector3 point = BlockVector3.at(x0, y0, z0);
                BaseBlock block = clipboard.getFullBlock(point);
                if (block.getNbtData() != null) {
                    Map<String, Tag> values = new HashMap<>(block.getNbtData().getValue());
                    // 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[] { x, y, z }));
                    tileEntities.add(new CompoundTag(values));
                }
                String blockKey = block.toImmutableState().getAsString();
                int blockId;
                if (palette.containsKey(blockKey)) {
                    blockId = palette.get(blockKey);
                } else {
                    blockId = paletteMax;
                    palette.put(blockKey, blockId);
                    paletteMax++;
                }
                while ((blockId & -128) != 0) {
                    buffer.write(blockId & 127 | 128);
                    blockId >>>= 7;
                }
                buffer.write(blockId);
            }
        }
    }
    schematic.put("PaletteMax", new IntTag(paletteMax));
    Map<String, Tag> paletteTag = new HashMap<>();
    palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
    schematic.put("Palette", new CompoundTag(paletteTag));
    schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
    schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities));
    // version 2 stuff
    if (clipboard.hasBiomes()) {
        writeBiomes(clipboard, schematic);
    }
    if (!clipboard.getEntities().isEmpty()) {
        writeEntities(clipboard, schematic);
    }
    return schematic;
}
Also used : StringTag(com.sk89q.jnbt.StringTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ByteArrayOutputStream(java.io.ByteArrayOutputStream) BlockVector3(com.sk89q.worldedit.math.BlockVector3) BaseBlock(com.sk89q.worldedit.world.block.BaseBlock) ListTag(com.sk89q.jnbt.ListTag) ShortTag(com.sk89q.jnbt.ShortTag) Region(com.sk89q.worldedit.regions.Region) StringTag(com.sk89q.jnbt.StringTag) ShortTag(com.sk89q.jnbt.ShortTag) IntArrayTag(com.sk89q.jnbt.IntArrayTag) ListTag(com.sk89q.jnbt.ListTag) IntTag(com.sk89q.jnbt.IntTag) ByteArrayTag(com.sk89q.jnbt.ByteArrayTag) CompoundTag(com.sk89q.jnbt.CompoundTag) Tag(com.sk89q.jnbt.Tag) IntTag(com.sk89q.jnbt.IntTag) CompoundTag(com.sk89q.jnbt.CompoundTag) ByteArrayTag(com.sk89q.jnbt.ByteArrayTag)

Aggregations

CompoundTag (com.sk89q.jnbt.CompoundTag)3 IntArrayTag (com.sk89q.jnbt.IntArrayTag)3 ListTag (com.sk89q.jnbt.ListTag)3 StringTag (com.sk89q.jnbt.StringTag)3 Tag (com.sk89q.jnbt.Tag)3 BlockVector3 (com.sk89q.worldedit.math.BlockVector3)3 Region (com.sk89q.worldedit.regions.Region)3 HashMap (java.util.HashMap)3 ByteArrayTag (com.sk89q.jnbt.ByteArrayTag)2 IntTag (com.sk89q.jnbt.IntTag)2 ShortTag (com.sk89q.jnbt.ShortTag)2 BlockArrayClipboard (com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard)2 BaseBlock (com.sk89q.worldedit.world.block.BaseBlock)2 BlockState (com.sk89q.worldedit.world.block.BlockState)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 ArrayList (java.util.ArrayList)2 FaweOutputStream (com.fastasyncworldedit.core.internal.io.FaweOutputStream)1 MutableBlockVector3 (com.fastasyncworldedit.core.math.MutableBlockVector3)1 NBTOutputStream (com.sk89q.jnbt.NBTOutputStream)1 NamedTag (com.sk89q.jnbt.NamedTag)1