Search in sources :

Example 11 with ListTag

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

the class MCEditSchematicReader method read.

@Override
public Clipboard read() throws IOException {
    // Schematic tag
    NamedTag rootTag = inputStream.readNamedTag();
    if (!rootTag.getName().equals("Schematic")) {
        throw new IOException("Tag 'Schematic' does not exist or is not first");
    }
    CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
    // Check
    Map<String, Tag> schematic = schematicTag.getValue();
    if (!schematic.containsKey("Blocks")) {
        throw new IOException("Schematic file is missing a 'Blocks' tag");
    }
    // Check type of Schematic
    String materials = requireTag(schematic, "Materials", StringTag.class).getValue();
    if (!materials.equals("Alpha")) {
        throw new IOException("Schematic file is not an Alpha schematic");
    }
    // ====================================================================
    // Metadata
    // ====================================================================
    BlockVector3 origin;
    Region region;
    // Get information
    short width = requireTag(schematic, "Width", ShortTag.class).getValue();
    short height = requireTag(schematic, "Height", ShortTag.class).getValue();
    short length = requireTag(schematic, "Length", ShortTag.class).getValue();
    try {
        int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue();
        int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue();
        int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue();
        BlockVector3 min = BlockVector3.at(originX, originY, originZ);
        int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue();
        int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue();
        int offsetZ = requireTag(schematic, "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));
    } catch (IOException ignored) {
        origin = BlockVector3.ZERO;
        region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
    }
    // ====================================================================
    // Blocks
    // ====================================================================
    // Get blocks
    byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue();
    byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue();
    byte[] addId = new byte[0];
    // Have to later combine IDs
    short[] blocks = new short[blockId.length];
    // the highest 4 bits are stored in a separate byte array.
    if (schematic.containsKey("AddBlocks")) {
        addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue();
    }
    // Combine the AddBlocks data with the first 8-bit block ID
    for (int index = 0; index < blockId.length; index++) {
        if ((index >> 1) >= addId.length) {
            // No corresponding AddBlocks index
            blocks[index] = (short) (blockId[index] & 0xFF);
        } else {
            if ((index & 1) == 0) {
                blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF));
            } else {
                blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF));
            }
        }
    }
    // Need to pull out tile entities
    final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class);
    List<Tag> tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue();
    BlockMap<BaseBlock> tileEntityBlocks = BlockMap.createForBaseBlock();
    for (Tag tag : tileEntities) {
        if (!(tag instanceof CompoundTag)) {
            continue;
        }
        CompoundTag t = (CompoundTag) tag;
        Map<String, Tag> values = new HashMap<>(t.getValue());
        String id = t.getString("id");
        values.put("id", new StringTag(convertBlockEntityId(id)));
        int x = t.getInt("x");
        int y = t.getInt("y");
        int z = t.getInt("z");
        int index = y * width * length + z * width + x;
        // position in schematics?
        if (index >= blocks.length) {
            LOGGER.warn("Skipping corrupt tile entity at position {} {} {} in schematic.", x, y, z);
            continue;
        }
        BlockState block = getBlockState(blocks[index], blockData[index]);
        BlockState newBlock = block;
        if (newBlock != null) {
            for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
                if (handler.isAffectedBlock(newBlock)) {
                    newBlock = handler.updateNBT(block, values).toImmutableState();
                    if (newBlock == null || values.isEmpty()) {
                        break;
                    }
                }
            }
        }
        if (values.isEmpty()) {
            t = null;
        } else {
            t = new CompoundTag(values);
        }
        if (fixer != null && t != null) {
            // FAWE start - BinaryTag
            t = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t.asBinaryTag(), -1));
        // FAWE end
        }
        BlockVector3 vec = BlockVector3.at(x, y, z);
        // Insert into the map if we have changed the block or have a tag
        BlockState blockToInsert = newBlock != null ? newBlock : (t != null ? block : null);
        if (blockToInsert != null) {
            BaseBlock baseBlock = t != null ? blockToInsert.toBaseBlock(new CompoundTag(t.getValue())) : blockToInsert.toBaseBlock();
            tileEntityBlocks.put(vec, baseBlock);
        }
    }
    BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
    clipboard.setOrigin(origin);
    Set<Integer> unknownBlocks = new HashSet<>();
    for (int x = 0; x < width; ++x) {
        for (int y = 0; y < height; ++y) {
            for (int z = 0; z < length; ++z) {
                int index = y * width * length + z * width + x;
                BlockVector3 pt = BlockVector3.at(x, y, z);
                BaseBlock state = Optional.ofNullable(tileEntityBlocks.get(pt)).orElseGet(() -> {
                    BlockState blockState = getBlockState(blocks[index], blockData[index]);
                    return blockState == null ? null : blockState.toBaseBlock();
                });
                try {
                    if (state != null) {
                        clipboard.setBlock(region.getMinimumPoint().add(pt), state);
                    } else {
                        short block = blocks[index];
                        byte data = blockData[index];
                        int combined = block << 8 | data;
                        if (unknownBlocks.add(combined)) {
                            LOGGER.warn("Unknown block when loading schematic: {} {}. This is most likely a" + "bad schematic.", block, data);
                        }
                    }
                } catch (WorldEditException ignored) {
                // BlockArrayClipboard won't throw this
                }
            }
        }
    }
    // ====================================================================
    // Entities
    // ====================================================================
    ListTag entityList = getTag(schematic, "Entities", ListTag.class);
    if (entityList != null) {
        List<Tag> entityTags = entityList.getValue();
        for (Tag tag : entityTags) {
            if (tag instanceof CompoundTag) {
                CompoundTag compound = (CompoundTag) tag;
                if (fixer != null) {
                    // FAWE start - BinaryTag
                    compound = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.ENTITY, compound.asBinaryTag(), -1));
                // FAWE end
                }
                String id = convertEntityId(compound.getString("id"));
                Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation"));
                if (!id.isEmpty()) {
                    EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT));
                    if (entityType != null) {
                        for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) {
                            if (compatibilityHandler.isAffectedEntity(entityType, compound)) {
                                compound = compatibilityHandler.updateNBT(entityType, compound);
                            }
                        }
                        BaseEntity state = new BaseEntity(entityType, compound);
                        clipboard.createEntity(location, state);
                    } else {
                        LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT));
                    }
                }
            }
        }
    }
    return clipboard;
}
Also used : StringTag(com.sk89q.jnbt.StringTag) HashMap(java.util.HashMap) CuboidRegion(com.sk89q.worldedit.regions.CuboidRegion) BaseBlock(com.sk89q.worldedit.world.block.BaseBlock) EntityNBTCompatibilityHandler(com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler) NBTCompatibilityHandler(com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler) EntityNBTCompatibilityHandler(com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler) NamedTag(com.sk89q.jnbt.NamedTag) CompoundTag(com.sk89q.jnbt.CompoundTag) IntTag(com.sk89q.jnbt.IntTag) HashSet(java.util.HashSet) BlockArrayClipboard(com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard) BaseEntity(com.sk89q.worldedit.entity.BaseEntity) IOException(java.io.IOException) BlockVector3(com.sk89q.worldedit.math.BlockVector3) ListTag(com.sk89q.jnbt.ListTag) ShortTag(com.sk89q.jnbt.ShortTag) EntityType(com.sk89q.worldedit.world.entity.EntityType) 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) 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) WorldEditException(com.sk89q.worldedit.WorldEditException) ByteArrayTag(com.sk89q.jnbt.ByteArrayTag) Location(com.sk89q.worldedit.util.Location)

Example 12 with ListTag

use of com.sk89q.jnbt.ListTag 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 13 with ListTag

use of com.sk89q.jnbt.ListTag 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)

Example 14 with ListTag

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

the class ExtentEntityCopy method transformNbtData.

/**
 * Transform NBT data in the given entity state and return a new instance
 * if the NBT data needs to be transformed.
 *
 * @param state the existing state
 * @return a new state or the existing one
 */
private BaseEntity transformNbtData(BaseEntity state) {
    CompoundTag tag = state.getNbtData();
    if (tag != null) {
        // Handle leashed entities
        Tag leashTag = tag.getValue().get("Leash");
        if (leashTag instanceof CompoundTag) {
            CompoundTag leashCompound = (CompoundTag) leashTag;
            if (leashCompound.containsKey("X")) {
                // leashed to a fence
                Vector3 tilePosition = Vector3.at(leashCompound.asInt("X"), leashCompound.asInt("Y"), leashCompound.asInt("Z"));
                BlockVector3 newLeash = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint();
                return new BaseEntity(state.getType(), tag.createBuilder().put("Leash", leashCompound.createBuilder().putInt("X", newLeash.getBlockX()).putInt("Y", newLeash.getBlockY()).putInt("Z", newLeash.getBlockZ()).build()).build());
            }
        }
        // Handle hanging entities (paintings, item frames, etc.)
        boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ");
        boolean hasFacing = tag.containsKey("Facing");
        // FAWE Start
        boolean hasRotation = tag.containsKey("Rotation");
        if (hasTilePosition) {
            Vector3 tilePosition = Vector3.at(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ"));
            BlockVector3 newTilePosition = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint();
            CompoundTagBuilder builder = tag.createBuilder().putInt("TileX", newTilePosition.getBlockX()).putInt("TileY", newTilePosition.getBlockY()).putInt("TileZ", newTilePosition.getBlockZ());
            if (hasFacing) {
                // Paintings have different facing values
                boolean isPainting = state.getType() == EntityTypes.PAINTING;
                Direction direction = isPainting ? MCDirections.fromHorizontalHanging(tag.asInt("Facing")) : MCDirections.fromHanging(tag.asInt("Facing"));
                if (direction != null) {
                    Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize();
                    Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL);
                    if (newDirection != null) {
                        builder.putByte("Facing", (byte) (isPainting ? MCDirections.toHorizontalHanging(newDirection) : MCDirections.toHanging(newDirection)));
                    }
                }
            }
            // FAWE start
            if (hasRotation) {
                ListTag orgrot = state.getNbtData().getListTag("Rotation");
                Vector3 orgDirection = new Location(source, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection();
                Vector3 newDirection = transform.apply(orgDirection).subtract(transform.apply(Vector3.ZERO)).normalize();
                builder.put("Rotation", new ListTag(FloatTag.class, Arrays.asList(new FloatTag((float) newDirection.toYaw()), new FloatTag((float) newDirection.toPitch()))));
            }
            return new BaseEntity(state.getType(), builder.build());
        } else if (hasRotation) {
            // armor stands do not have a tile pos
            CompoundTagBuilder builder = tag.createBuilder();
            ListTag orgrot = state.getNbtData().getListTag("Rotation");
            Vector3 orgDirection = new Location(source, 0, 0, 0, orgrot.getFloat(0), orgrot.getFloat(1)).getDirection();
            Vector3 newDirection = transform.apply(orgDirection).subtract(transform.apply(Vector3.ZERO)).normalize();
            builder.put("Rotation", new ListTag(FloatTag.class, Arrays.asList(new FloatTag((float) newDirection.toYaw()), new FloatTag((float) newDirection.toPitch()))));
            return new BaseEntity(state.getType(), builder.build());
        // FAWE end
        }
    }
    return state;
}
Also used : FloatTag(com.sk89q.jnbt.FloatTag) BaseEntity(com.sk89q.worldedit.entity.BaseEntity) BlockVector3(com.sk89q.worldedit.math.BlockVector3) Vector3(com.sk89q.worldedit.math.Vector3) ListTag(com.sk89q.jnbt.ListTag) FloatTag(com.sk89q.jnbt.FloatTag) CompoundTag(com.sk89q.jnbt.CompoundTag) Tag(com.sk89q.jnbt.Tag) BlockVector3(com.sk89q.worldedit.math.BlockVector3) Direction(com.sk89q.worldedit.util.Direction) ListTag(com.sk89q.jnbt.ListTag) CompoundTag(com.sk89q.jnbt.CompoundTag) CompoundTagBuilder(com.sk89q.jnbt.CompoundTagBuilder) Location(com.sk89q.worldedit.util.Location)

Aggregations

ListTag (com.sk89q.jnbt.ListTag)14 CompoundTag (com.sk89q.jnbt.CompoundTag)12 Tag (com.sk89q.jnbt.Tag)12 IntTag (com.sk89q.jnbt.IntTag)10 StringTag (com.sk89q.jnbt.StringTag)10 ShortTag (com.sk89q.jnbt.ShortTag)8 ArrayList (java.util.ArrayList)8 ByteArrayTag (com.sk89q.jnbt.ByteArrayTag)6 IntArrayTag (com.sk89q.jnbt.IntArrayTag)6 BlockVector3 (com.sk89q.worldedit.math.BlockVector3)6 HashMap (java.util.HashMap)6 BaseEntity (com.sk89q.worldedit.entity.BaseEntity)5 Location (com.sk89q.worldedit.util.Location)5 BlockState (com.sk89q.worldedit.world.block.BlockState)5 FloatTag (com.sk89q.jnbt.FloatTag)4 BlockArrayClipboard (com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard)4 Region (com.sk89q.worldedit.regions.Region)4 BaseBlock (com.sk89q.worldedit.world.block.BaseBlock)4 DoubleTag (com.sk89q.jnbt.DoubleTag)3 NamedTag (com.sk89q.jnbt.NamedTag)3