From 0b689c90eb494f358bcd5825d50790f7589bbd68 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Wed, 8 Jan 2025 12:49:17 +0100 Subject: [PATCH] Add new Schematic reader --- .../de/steamwar/core/ChaosSchemReader.java | 150 +++++++++++++----- .../de/steamwar/core/WorldEditWrapper21.java | 3 +- 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java index 8aab6440..4553e2d6 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/ChaosSchemReader.java @@ -20,6 +20,8 @@ package de.steamwar.core; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.factory.BlockFactory; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -29,18 +31,28 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.block.BlockState; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.*; import java.io.DataInputStream; import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class ChaosSchemReader implements ClipboardReader { private final DataInputStream stream; - public ChaosSchemReader(DataInputStream stream) { - this.stream = stream; + public ChaosSchemReader(InputStream stream) { + if (stream instanceof DataInputStream dis) { + this.stream = dis; + } else { + this.stream = new DataInputStream(stream); + } } @Override @@ -63,6 +75,8 @@ public class ChaosSchemReader implements ClipboardReader { } else { readSchemTag(); } + + return constructSchematic(); } private int version; @@ -75,17 +89,39 @@ public class ChaosSchemReader implements ClipboardReader { private int[] offset = new int[3]; - private Map palette = new HashMap<>(); + private Map palette = new HashMap<>(); private int[] blocks; - private Map metadata; + private LinCompoundTag metadata; + + private Map tileEntityMap = new HashMap<>(); private Clipboard constructSchematic() { BlockVector3 min = BlockVector3.at(offset[0], offset[1], offset[2]); - Region region = new CuboidRegion(min); + Region region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + + clipboard.setOrigin(min); + + int index = 0; + for (int block : blocks) { + int y = index / (width * length); + int z = (index % (width * length)) / width; + int x = (index++ % (width * length)) % width; + + BlockState state = palette.get(block); + BlockVector3 pt = BlockVector3.at(x, y, z); + + if (tileEntityMap.containsKey(pt)) { + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(tileEntityMap.get(pt))); + } else { + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state); + } + } + + return clipboard; } private void readSchemTag() throws IOException { @@ -102,15 +138,16 @@ public class ChaosSchemReader implements ClipboardReader { this.fixer = platform.getDataFixer(); } } - case "Metadata" -> metadata = (Map) readByType((byte) 0x0A); + case "Metadata" -> metadata = readCompound(); case "Width" -> width = stream.readUnsignedShort(); case "Height" -> height = stream.readUnsignedShort(); case "Length" -> length = stream.readUnsignedShort(); - case "Offset" -> offset = readIntArray(); + case "Offset" -> offset = readIntArray().value(); case "PaletteMax" -> stream.skipNBytes(4); case "Palette" -> readPalette(); case "BlockData" -> readBlockData(); case "Blocks" -> readBlockContainer(); + case "BlockEntities" -> readTileEntities(); default -> skipByType(type); } @@ -122,14 +159,38 @@ public class ChaosSchemReader implements ClipboardReader { switch (name) { case "Palette" -> readPalette(); case "Data" -> readBlockData(); + case "BlockEntities" -> readTileEntities(); default -> skipByType(type); } }); } + private void readTileEntities() throws IOException { + LinListTag list = (LinListTag) readArray(); + + list.value().forEach(linCompoundTag -> { + List pos = linCompoundTag.getListTag("Pos", LinTagType.intTag()).value(); + + BlockVector3 pt = BlockVector3.at(pos.get(0).value(), pos.get(1).value(), pos.get(2).value()); + + if (fixer != null) { + linCompoundTag = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, LinCompoundTag.of(linCompoundTag.value()), dataVersion); + } + + tileEntityMap.put(pt, linCompoundTag); + }); + } + private void readPalette() throws IOException { - parseCompoundTag((aByte, string) -> palette.put(string, stream.readInt())); + BlockFactory bf = WorldEdit.getInstance().getBlockFactory(); + + ParserContext context = new ParserContext(); + context.setRestricted(true); + context.setTryLegacy(false); + context.setPreferringWildcard(false); + + parseCompoundTag((aByte, string) -> palette.put(stream.readInt(), bf.parseFromInput(string, context).toImmutableState())); } private static final int SEGMENT_BITS = 0x7F; @@ -168,17 +229,6 @@ public class ChaosSchemReader implements ClipboardReader { } } - private int[] readIntArray() throws IOException { - int length = stream.readInt(); - int[] arr = new int[length]; - - for (int i = 0; i < length; i++) { - arr[i] = stream.readInt(); - } - - return arr; - } - private byte[] readByteArray() throws IOException { return stream.readNBytes(stream.readInt()); } @@ -208,45 +258,67 @@ public class ChaosSchemReader implements ClipboardReader { } } - private Object readByType(byte type) throws IOException { + private LinTag readByType(byte type) throws IOException { return switch (type) { case 0x00 -> null; - case 0x01 -> stream.readByte(); - case 0x02 -> stream.readShort(); - case 0x03 -> stream.readInt(); - case 0x04 -> stream.readLong(); - case 0x05 -> stream.readFloat(); - case 0x06 -> stream.readDouble(); - case 0x07 -> stream.readNBytes(stream.readInt()); - case 0x08 -> stream.readUTF(); + case 0x01 -> LinByteTag.of(stream.readByte()); + case 0x02 -> LinShortTag.of(stream.readShort()); + case 0x03 -> LinIntTag.of(stream.readInt()); + case 0x04 -> LinLongTag.of(stream.readLong()); + case 0x05 -> LinFloatTag.of(stream.readFloat()); + case 0x06 -> LinDoubleTag.of(stream.readDouble()); + case 0x07 -> LinByteArrayTag.of(stream.readNBytes(stream.readInt())); + case 0x08 -> LinStringTag.of(stream.readUTF()); case 0x09 -> readArray(); case 0x0A -> readCompound(); - case 0x0B -> stream.skipNBytes(4L * stream.readInt()); - case 0x0C -> stream.skipNBytes(8L * stream.readInt()); + case 0x0B -> readIntArray(); + case 0x0C -> readLongArray(); default -> error("Invalid Type"); }; } - private Object[] readArray() throws IOException { - byte t = stream.readByte(); + private LinIntArrayTag readIntArray() throws IOException { int length = stream.readInt(); - Object[] obj = new Object[length]; + + int[] ints = new int[length]; for (int i = 0; i < length; i++) { - obj[i] = readByType(t); + ints[i] = stream.readInt(); } - return obj; + return LinIntArrayTag.of(ints); } - private Map readCompound() throws IOException { - Map entries = new HashMap<>(); + private LinLongArrayTag readLongArray() throws IOException { + int length = stream.readInt(); + + long[] longs = new long[length]; + for (int i = 0; i < length; i++) { + longs[i] = stream.readInt(); + } + + return LinLongArrayTag.of(longs); + } + + private LinListTag readArray() throws IOException { + byte t = stream.readByte(); + int length = stream.readInt(); + List> obj = new ArrayList<>(length); + for (int i = 0; i < length; i++) { + obj.add(readByType(t)); + } + + return LinListTag.of(LinTagType.fromId(LinTagId.fromId(t)), obj); + } + + private LinCompoundTag readCompound() throws IOException { + Map> entries = new HashMap<>(); parseCompoundTag((type, name) -> entries.put(name, readByType(type))); - return entries; + return LinCompoundTag.of(entries); } - private void error(String message) { + private T error(String message) { throw new IllegalStateException("Could not read Schem: " + message); } diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java index 52947f3a..e2ab7992 100644 --- a/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java +++ b/SpigotCore/SpigotCore_21/src/de/steamwar/core/WorldEditWrapper21.java @@ -71,8 +71,7 @@ public class WorldEditWrapper21 implements WorldEditWrapper { public Clipboard getClipboard(InputStream is, NodeData.SchematicFormat schemFormat) throws IOException { return switch (schemFormat) { case MCEDIT -> new MCEditSchematicReader(new NBTInputStream(is)).read(); - case SPONGE_V2 -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(is))).read(); - case SPONGE_V3 -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(is))).read(); + case SPONGE_V2, SPONGE_V3 -> new ChaosSchemReader(is).read(); }; }