public CuboidClipboard load(InputStream stream) throws IOException, DataException { NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(stream)); Vector origin = new Vector(); Vector offset = new Vector(); // Schematic tag NamedTag rootTag = nbtStream.readNamedTag(); nbtStream.close(); if (!rootTag.getName().equals("Schematic")) { throw new DataException("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 DataException("Schematic file is missing a \"Blocks\" tag"); } // Get information short width = getChildTag(schematic, "Width", ShortTag.class).getValue(); short length = getChildTag(schematic, "Length", ShortTag.class).getValue(); short height = getChildTag(schematic, "Height", ShortTag.class).getValue(); try { int originX = getChildTag(schematic, "WEOriginX", IntTag.class).getValue(); int originY = getChildTag(schematic, "WEOriginY", IntTag.class).getValue(); int originZ = getChildTag(schematic, "WEOriginZ", IntTag.class).getValue(); origin = new Vector(originX, originY, originZ); } catch (DataException e) { // No origin data } try { int offsetX = getChildTag(schematic, "WEOffsetX", IntTag.class).getValue(); int offsetY = getChildTag(schematic, "WEOffsetY", IntTag.class).getValue(); int offsetZ = getChildTag(schematic, "WEOffsetZ", IntTag.class).getValue(); offset = new Vector(offsetX, offsetY, offsetZ); } catch (DataException e) { // No offset data } // Check type of Schematic String materials = getChildTag(schematic, "Materials", StringTag.class).getValue(); if (!materials.equals("Alpha")) { throw new DataException("Schematic file is not an Alpha schematic"); } // Get blocks byte[] blockId = getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue(); byte[] blockData = getChildTag(schematic, "Data", ByteArrayTag.class).getValue(); byte[] addId = new byte[0]; short[] blocks = new short[blockId.length]; // Have to later combine IDs // We support 4096 block IDs using the same method as vanilla Minecraft, where // the highest 4 bits are stored in a separate byte array. if (schematic.containsKey("AddBlocks")) { addId = getChildTag(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 List<Tag> tileEntities = getChildTag(schematic, "TileEntities", ListTag.class).getValue(); Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<BlockVector, Map<String, Tag>>(); for (Tag tag : tileEntities) { if (!(tag instanceof CompoundTag)) continue; CompoundTag t = (CompoundTag) tag; int x = 0; int y = 0; int z = 0; Map<String, Tag> values = new HashMap<String, Tag>(); for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) { if (entry.getKey().equals("x")) { if (entry.getValue() instanceof IntTag) { x = ((IntTag) entry.getValue()).getValue(); } } else if (entry.getKey().equals("y")) { if (entry.getValue() instanceof IntTag) { y = ((IntTag) entry.getValue()).getValue(); } } else if (entry.getKey().equals("z")) { if (entry.getValue() instanceof IntTag) { z = ((IntTag) entry.getValue()).getValue(); } } values.put(entry.getKey(), entry.getValue()); } BlockVector vec = new BlockVector(x, y, z); tileEntitiesMap.put(vec, values); } Vector size = new Vector(width, height, length); CuboidClipboard clipboard = new CuboidClipboard(size); clipboard.setOrigin(origin); clipboard.setOffset(offset); 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; BlockVector pt = new BlockVector(x, y, z); BaseBlock block = getBlockForId(blocks[index], blockData[index]); if (tileEntitiesMap.containsKey(pt)) { block.setNbtData(new CompoundTag(tileEntitiesMap.get(pt))); } clipboard.setBlock(pt, block); } } } return clipboard; }