From a75d9e896b56589f06d8431977258552648f3a99 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 2 Aug 2018 14:15:49 +1000 Subject: [PATCH] Start work on the Sponge schematic format. This should work but it may not, it's untested. --- .../com/sk89q/worldedit/blocks/BaseBlock.java | 12 - .../worldedit/command/SchematicCommands.java | 2 +- .../clipboard/io/BuiltInClipboardFormat.java | 67 +++++- ...Reader.java => MCEditSchematicReader.java} | 40 +--- .../clipboard/io/NBTSchematicReader.java | 44 ++++ .../clipboard/io/SpongeSchematicReader.java | 220 ++++++++++++++++++ .../clipboard/io/SpongeSchematicWriter.java | 174 ++++++++++++++ .../sk89q/worldedit/world/item/ItemType.java | 18 -- 8 files changed, 499 insertions(+), 78 deletions(-) rename worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/{SchematicReader.java => MCEditSchematicReader.java} (90%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java index 9fd469057..a3ebc113d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseBlock.java @@ -111,18 +111,6 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { this(other.toImmutableState(), other.getNbtData()); } - /** - * Get the block's data value. - * - * Broken - do not use - * - * @return data value (0-15) - */ - @Deprecated - public int getData() { - return 0; - } - /** * Gets a map of state to statevalue * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index 2f85734e7..cc8df7c24 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java @@ -133,7 +133,7 @@ public class SchematicCommands { ) @Deprecated @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) - public void save(Player player, LocalSession session, @Optional("schematic") String formatName, String filename) throws CommandException, WorldEditException { + public void save(Player player, LocalSession session, @Optional("sponge") String formatName, String filename) throws CommandException, WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 46ee0eab3..574c5b881 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.google.common.collect.ImmutableSet; import com.sk89q.jnbt.NBTConstants; import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; import java.io.DataInputStream; import java.io.File; @@ -31,6 +32,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Set; import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; /** * A collection of supported clipboard formats. @@ -38,7 +40,7 @@ import java.util.zip.GZIPInputStream; public enum BuiltInClipboardFormat implements ClipboardFormat { /** - * The Schematic format used by many software. + * The Schematic format used by MCEdit. */ MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") { @@ -50,7 +52,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); - return new SchematicReader(nbtStream); + return new MCEditSchematicReader(nbtStream); } @Override @@ -60,25 +62,66 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public boolean isFormat(File file) { - DataInputStream str = null; - try { - str = new DataInputStream(new GZIPInputStream(new FileInputStream(file))); + try (DataInputStream str = new DataInputStream(new GZIPInputStream(new FileInputStream(file)))) { if ((str.readByte() & 0xFF) != NBTConstants.TYPE_COMPOUND) { return false; } byte[] nameBytes = new byte[str.readShort() & 0xFFFF]; str.readFully(nameBytes); String name = new String(nameBytes, NBTConstants.CHARSET); - return name.equals("Schematic"); + if (!name.equals("Schematic")) { + return false; + } + str.readByte(); // Ignore + nameBytes = new byte[str.readShort() & 0xFFFF]; + str.readFully(nameBytes); + name = new String(nameBytes, NBTConstants.CHARSET); + return !name.equals("Version"); } catch (IOException e) { return false; - } finally { - if (str != null) { - try { - str.close(); - } catch (IOException ignored) { - } + } + } + }, + SPONGE_SCHEMATIC("sponge", "schem") { + + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); + return new SpongeSchematicReader(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); + return new SpongeSchematicWriter(nbtStream); + } + + @Override + public boolean isFormat(File file) { + try (DataInputStream str = new DataInputStream(new GZIPInputStream(new FileInputStream(file)))) { + if ((str.readByte() & 0xFF) != NBTConstants.TYPE_COMPOUND) { + return false; } + byte[] nameBytes = new byte[str.readShort() & 0xFFFF]; + str.readFully(nameBytes); + String name = new String(nameBytes, NBTConstants.CHARSET); + if (!name.equals("Schematic")) { + return false; + } + if ((str.readByte() & 0xFF) != NBTConstants.TYPE_INT) { + return false; + } + nameBytes = new byte[str.readShort() & 0xFFFF]; + str.readFully(nameBytes); + name = new String(nameBytes, NBTConstants.CHARSET); + return name.equals("Version"); + } catch (IOException e) { + return false; } } }; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java similarity index 90% rename from worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index 4e83fb301..13d99b452 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -56,20 +56,19 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import javax.annotation.Nullable; - /** - * Reads schematic files based that are compatible with MCEdit and other editors. + * Reads schematic files that are compatible with MCEdit and other editors. */ -public class SchematicReader implements ClipboardReader { +public class MCEditSchematicReader extends NBTSchematicReader { private static final List COMPATIBILITY_HANDLERS = new ArrayList<>(); static { COMPATIBILITY_HANDLERS.add(new SignCompatibilityHandler()); + // TODO Add a handler for skulls, flower pots, note blocks, etc. } - private static final Logger log = Logger.getLogger(SchematicReader.class.getCanonicalName()); + private static final Logger log = Logger.getLogger(MCEditSchematicReader.class.getCanonicalName()); private final NBTInputStream inputStream; /** @@ -77,7 +76,7 @@ public class SchematicReader implements ClipboardReader { * * @param inputStream the input stream to read from */ - public SchematicReader(NBTInputStream inputStream) { + public MCEditSchematicReader(NBTInputStream inputStream) { checkNotNull(inputStream); this.inputStream = inputStream; } @@ -282,35 +281,6 @@ public class SchematicReader implements ClipboardReader { return clipboard; } - private static T requireTag(Map items, String key, Class expected) throws IOException { - if (!items.containsKey(key)) { - throw new IOException("Schematic file is missing a \"" + key + "\" tag"); - } - - Tag tag = items.get(key); - if (!expected.isInstance(tag)) { - throw new IOException(key + " tag is not of tag type " + expected.getName()); - } - - return expected.cast(tag); - } - - @Nullable - private static T getTag(CompoundTag tag, Class expected, String key) { - Map items = tag.getValue(); - - if (!items.containsKey(key)) { - return null; - } - - Tag test = items.get(key); - if (!expected.isInstance(test)) { - return null; - } - - return expected.cast(test); - } - @Override public void close() throws IOException { inputStream.close(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java new file mode 100644 index 000000000..d5d6d0bf8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -0,0 +1,44 @@ +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; + +import java.io.IOException; +import java.util.Map; + +import javax.annotation.Nullable; + +/** + * Base class for NBT schematic readers + */ +public abstract class NBTSchematicReader implements ClipboardReader { + + protected static T requireTag(Map items, String key, Class expected) throws IOException { + if (!items.containsKey(key)) { + throw new IOException("Schematic file is missing a \"" + key + "\" tag"); + } + + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new IOException(key + " tag is not of tag type " + expected.getName()); + } + + return expected.cast(tag); + } + + @Nullable + protected static T getTag(CompoundTag tag, Class expected, String key) { + Map items = tag.getValue(); + + if (!items.containsKey(key)) { + return null; + } + + Tag test = items.get(key); + if (!expected.isInstance(test)) { + return null; + } + + return expected.cast(test); + } +} 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 new file mode 100644 index 000000000..a1aa21a03 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java @@ -0,0 +1,220 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NamedTag; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Reads schematic files using the Sponge Schematic Specification. + */ +public class SpongeSchematicReader extends NBTSchematicReader { + + private static final List COMPATIBILITY_HANDLERS = new ArrayList<>(); + + static { + // If NBT Compat handlers are needed - add them here. + } + + private static final Logger log = Logger.getLogger(SpongeSchematicReader.class.getCanonicalName()); + private final NBTInputStream inputStream; + + /** + * Create a new instance. + * + * @param inputStream the input stream to read from + */ + public SpongeSchematicReader(NBTInputStream inputStream) { + checkNotNull(inputStream); + this.inputStream = inputStream; + } + + @Override + public Clipboard read() throws IOException { + 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 schematic = schematicTag.getValue(); + int version = requireTag(schematic, "Version", IntTag.class).getValue(); + switch (version) { + case 1: + return readVersion1(schematic); + default: + throw new IOException("This schematic version is currently not supported"); + } + } + + private Clipboard readVersion1(Map schematic) throws IOException { + Vector origin; + Region region; + + Map metadata = requireTag(schematic, "Metadata", CompoundTag.class).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(); + + int[] offsetParts = requireTag(schematic, "Offset", IntArrayTag.class).getValue(); + if (offsetParts.length != 3) { + throw new IOException("Invalid offset specified in schematic."); + } + + Vector offset = new Vector(offsetParts[0], offsetParts[1], offsetParts[2]); + + if (metadata.containsKey("WEOriginX")) { + // We appear to have WorldEdit Metadata + int originX = requireTag(metadata, "WEOriginX", IntTag.class).getValue(); + int originY = requireTag(metadata, "WEOriginY", IntTag.class).getValue(); + int originZ = requireTag(metadata, "WEOriginZ", IntTag.class).getValue(); + Vector min = new Vector(originX, originY, originZ); + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(Vector.ONE)); + } else { + origin = Vector.ZERO.subtract(offset); + region = new CuboidRegion(origin, origin.add(width, height, length).subtract(Vector.ONE)); + } + + int paletteMax = requireTag(schematic, "PaletteMax", IntTag.class).getValue(); + Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); + if (paletteObject.size() != paletteMax) { + throw new IOException("Differing given palette size to actual size"); + } + + Map palette = new HashMap<>(); + + ParserContext parserContext = new ParserContext(); + + for (String palettePart : paletteObject.keySet()) { + int id = requireTag(paletteObject, palettePart, IntTag.class).getValue(); + BlockState state; + try { + state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); + } catch (InputParseException e) { + throw new IOException("Invalid BlockState in schematic: " + palettePart + ". Are you missing a mod of using a schematic made in a newer version of Minecraft?"); + } + palette.put(id, state); + } + + byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); + + Map> tileEntitiesMap = new HashMap<>(); + try { + List> tileEntityTags = requireTag(schematic, "TileEntities", ListTag.class).getValue().stream() + .map(tag -> (CompoundTag) tag) + .map(CompoundTag::getValue) + .collect(Collectors.toList()); + + for (Map tileEntity : tileEntityTags) { + int[] pos = requireTag(schematic, "Pos", IntArrayTag.class).getValue(); + tileEntitiesMap.put(new BlockVector(pos[0], pos[1], pos[2]), tileEntity); + } + } catch (Exception e) { + throw new IOException("Failed to load Tile Entities: " + e.getMessage()); + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + + int index = 0; + int i = 0; + int value = 0; + int varint_length = 0; + while (i < blocks.length) { + value = 0; + varint_length = 0; + + while (true) { + value |= (blocks[i] & 127) << (varint_length++ * 7); + if (varint_length > 5) { + throw new RuntimeException("VarInt too big (probably corrupted data)"); + } + if ((blocks[i] & 128) != 128) { + i++; + break; + } + i++; + } + // index = (y * length + 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); + BlockVector pt = new BlockVector(x, y, z); + try { + if (tileEntitiesMap.containsKey(pt)) { + Map values = tileEntitiesMap.get(pt); + for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { + if (handler.isAffectedBlock(state)) { + handler.updateNBT(state, values); + } + } + clipboard.setBlock(pt, new BaseBlock(state, new CompoundTag(values))); + } else { + clipboard.setBlock(pt, state); + } + } catch (WorldEditException e) { + throw new IOException("Failed to load a block in the schematic"); + } + + index++; + } + + return clipboard; + } + + @Override + public void close() throws IOException { + inputStream.close(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java new file mode 100644 index 000000000..fc97a35f6 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java @@ -0,0 +1,174 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.regions.Region; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Writes schematic files using the Sponge schematic format. + */ +public class SpongeSchematicWriter implements ClipboardWriter { + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final NBTOutputStream outputStream; + + /** + * Create a new schematic writer. + * + * @param outputStream the output stream to write to + */ + public SpongeSchematicWriter(NBTOutputStream outputStream) { + checkNotNull(outputStream); + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard) throws IOException { + // For now always write the latest version. Maybe provide support for earlier if more appear. + outputStream.writeNamedTag("Schematic", new CompoundTag(write1(clipboard))); + } + + /** + * Writes a version 1 schematic file. + * + * @param clipboard The clipboard + * @return The schematic map + * @throws IOException If an error occurs + */ + private Map write1(Clipboard clipboard) throws IOException { + Region region = clipboard.getRegion(); + Vector origin = clipboard.getOrigin(); + Vector min = region.getMinimumPoint(); + Vector 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 schematic = new HashMap<>(); + schematic.put("Version", new IntTag(1)); + + Map metadata = new HashMap<>(); + metadata.put("WEOriginX", new IntTag(min.getBlockX())); + metadata.put("WEOriginY", new IntTag(min.getBlockY())); + metadata.put("WEOriginZ", new IntTag(min.getBlockZ())); + + 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)); + + schematic.put("Offset", new IntArrayTag(new int[]{ + offset.getBlockX(), + offset.getBlockY(), + offset.getBlockZ(), + })); + + int paletteMax = 0; + Map palette = new HashMap<>(); + + List tileEntities = new ArrayList<>(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); + + for (Vector point : region) { + BaseBlock block = clipboard.getFullBlock(point); + if (block.getNbtData() != null) { + Map values = new HashMap<>(); + for (Map.Entry entry : block.getNbtData().getValue().entrySet()) { + values.put(entry.getKey(), entry.getValue()); + } + + values.put("Id", new StringTag(block.getNbtId())); + values.put("Pos", new IntArrayTag(new int[]{ + point.getBlockX(), + point.getBlockY(), + point.getBlockZ() + })); + + CompoundTag tileEntityTag = new CompoundTag(values); + tileEntities.add(tileEntityTag); + } + + 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 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("TileEntities", new ListTag(CompoundTag.class, tileEntities)); + + return schematic; + } + + @Override + public void close() throws IOException { + outputStream.close(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index d49f28ddc..6452451d0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -23,7 +23,6 @@ import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BundledItemData; -import com.sk89q.worldedit.world.registry.LegacyMapper; import javax.annotation.Nullable; @@ -79,23 +78,6 @@ public class ItemType { return BlockTypes.get(this.id); } - /** - * Gets the legacy ID. Needed for legacy reasons. - * - * DO NOT USE THIS. - * - * @return legacy id or 0, if unknown - */ - @Deprecated - public int getLegacyId() { - int ids[] = LegacyMapper.getInstance().getLegacyFromItem(this); - if (ids != null) { - return ids[0]; - } else { - return 0; - } - } - @Override public int hashCode() { return this.id.hashCode();