From 599a08aa2b4167a781a07a0ab63845ec2ad5cb5c Mon Sep 17 00:00:00 2001 From: Connor Date: Sat, 7 Sep 2024 19:52:42 +0100 Subject: [PATCH] Bump minestom version to support 1.21.1 for testing Create BlockEntity record to support block entity format across versions Apply Block data when applying rotations Add empty block data when generating a new schematic, will be replaced Add loading tile entity support for v1, v2, and v3 schematics --- gradle/libs.versions.toml | 2 +- .../net/hollowcube/schem/BlockEntity.java | 25 ++++++++ .../net/hollowcube/schem/CoordinateUtil.java | 4 ++ .../java/net/hollowcube/schem/Schematic.java | 18 +++++- .../hollowcube/schem/SchematicBuilder.java | 3 +- .../net/hollowcube/schem/SchematicReader.java | 60 +++++++++++++++++-- 6 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/hollowcube/schem/BlockEntity.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0623ace..b85b41f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ metadata.format.version = "1.1" [versions] -minestom = "1_20_5-323c75f8a5" +minestom = "b0bad7e180" logback = "1.4.5" # For tests only nexuspublish = "1.3.0" diff --git a/src/main/java/net/hollowcube/schem/BlockEntity.java b/src/main/java/net/hollowcube/schem/BlockEntity.java new file mode 100644 index 0000000..dc617f8 --- /dev/null +++ b/src/main/java/net/hollowcube/schem/BlockEntity.java @@ -0,0 +1,25 @@ +package net.hollowcube.schem; + +import net.kyori.adventure.nbt.CompoundBinaryTag; +import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Vec; + +public record BlockEntity(String id, Point point, CompoundBinaryTag trimmedTag) { + + public static BlockEntity fromV3(CompoundBinaryTag blockTag) { + int[] position = blockTag.getIntArray("Pos"); + return new BlockEntity(blockTag.getString("Id"), new Vec(position[0], position[1], position[2]), blockTag.getCompound("Data")); + } + + public static BlockEntity fromV1(CompoundBinaryTag entityCompound) { + int[] position = entityCompound.getIntArray("Pos"); + String id = entityCompound.getString("Id"); + CompoundBinaryTag stripped = CompoundBinaryTag + .builder() + .put(entityCompound) + .remove("Pos") + .remove("Id") + .remove("Extra").build(); + return new BlockEntity(id, new Vec(position[0], position[1], position[2]), stripped); + } +} diff --git a/src/main/java/net/hollowcube/schem/CoordinateUtil.java b/src/main/java/net/hollowcube/schem/CoordinateUtil.java index cdf6df8..ea4ff15 100644 --- a/src/main/java/net/hollowcube/schem/CoordinateUtil.java +++ b/src/main/java/net/hollowcube/schem/CoordinateUtil.java @@ -120,4 +120,8 @@ private static String rotate90(String in) { }; } + public static String getCoordinateKey(int x, int y, int z) { + return x + "," + y + "," + z; + } + } diff --git a/src/main/java/net/hollowcube/schem/Schematic.java b/src/main/java/net/hollowcube/schem/Schematic.java index 2be99e1..f06a369 100644 --- a/src/main/java/net/hollowcube/schem/Schematic.java +++ b/src/main/java/net/hollowcube/schem/Schematic.java @@ -1,16 +1,20 @@ package net.hollowcube.schem; +import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.batch.BatchOption; import net.minestom.server.instance.batch.RelativeBlockBatch; import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.utils.Utils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.UnaryOperator; @@ -23,11 +27,12 @@ public record Schematic( Point size, Point offset, Block[] palette, - byte[] blocks + byte[] blocks, + Map blockEntities ) { private static final System.Logger logger = System.getLogger(Schematic.class.getName()); - static final Schematic EMPTY = new Schematic(Vec.ZERO, Vec.ZERO, new Block[0], new byte[0]); + static final Schematic EMPTY = new Schematic(Vec.ZERO, Vec.ZERO, new Block[0], new byte[0], Collections.emptyMap()); public Schematic { palette = Arrays.copyOf(palette, palette.length); @@ -71,6 +76,15 @@ public void apply(@NotNull Rotation rotation, @NotNull BiConsumer block = Block.AIR; } + // If block entity is present at the current coordinate, apply its handler + // and NBT data to the block. + BlockEntity blockEntity = blockEntities.get(CoordinateUtil.getCoordinateKey(x, y, z)); + if(blockEntity != null) { + BlockHandler handler = MinecraftServer.getBlockManager().getHandlerOrDummy(blockEntity.id()); + block = block.withHandler(handler); + block = blockEntity.trimmedTag().size() > 0 ? block.withNbt(blockEntity.trimmedTag()) : block; + } + applicator.accept( CoordinateUtil.rotatePos(offset.add(x, y, z), rotation), CoordinateUtil.rotateBlock(block, rotation)); diff --git a/src/main/java/net/hollowcube/schem/SchematicBuilder.java b/src/main/java/net/hollowcube/schem/SchematicBuilder.java index d5419a9..b808b97 100644 --- a/src/main/java/net/hollowcube/schem/SchematicBuilder.java +++ b/src/main/java/net/hollowcube/schem/SchematicBuilder.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -116,6 +117,6 @@ public void setOffset(@NotNull Point point) { var out = new byte[blockBytes.position()]; blockBytes.flip().get(out); - return new Schematic(size, offset, palette, out); + return new Schematic(size, offset, palette, out, Collections.emptyMap()); } } diff --git a/src/main/java/net/hollowcube/schem/SchematicReader.java b/src/main/java/net/hollowcube/schem/SchematicReader.java index 885678b..2b4c13b 100644 --- a/src/main/java/net/hollowcube/schem/SchematicReader.java +++ b/src/main/java/net/hollowcube/schem/SchematicReader.java @@ -3,11 +3,9 @@ import net.hollowcube.schem.blockpalette.BlockPaletteParser; import net.hollowcube.schem.blockpalette.CommandBlockPaletteParser; -import net.kyori.adventure.nbt.BinaryTagIO; -import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.kyori.adventure.nbt.IntBinaryTag; -import net.minestom.server.command.builder.arguments.minecraft.ArgumentBlockState; +import net.kyori.adventure.nbt.*; import net.minestom.server.command.builder.exception.ArgumentSyntaxException; +import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; import net.minestom.server.utils.validate.Check; @@ -15,6 +13,7 @@ import java.io.InputStream; import java.nio.file.Path; +import java.util.HashMap; import java.util.Map; /** @@ -61,6 +60,13 @@ public SchematicReader withBlockPaletteParser(BlockPaletteParser parser) { } } + /** + * Reads a Sponge Schematic from a CompoundBinaryTag. + * @see Sponge Schematic Specification + * + * @param tag A CompoundBinaryTag containing the schematic data + * @param version The schematic specification version (1, 2, or 3) + */ private @NotNull Schematic read(@NotNull CompoundBinaryTag tag, int version) { short width = tag.getShort("Width"); short height = tag.getShort("Height"); @@ -80,6 +86,9 @@ public SchematicReader withBlockPaletteParser(BlockPaletteParser parser) { CompoundBinaryTag palette; byte[] blockArray; Integer paletteSize; + Map blockEntitiesMap = new HashMap<>(); + + if (version == 3) { var blockEntries = tag.getCompound("Blocks"); Check.notNull(blockEntries, "Missing required field 'Blocks'"); @@ -89,6 +98,35 @@ public SchematicReader withBlockPaletteParser(BlockPaletteParser parser) { blockArray = blockEntries.getByteArray("Data"); Check.notNull(blockArray, "Missing required field 'Blocks.Data'"); paletteSize = palette.size(); + ListBinaryTag blockEntities = blockEntries.getList("BlockEntities"); + Check.notNull(blockEntities, "Missing required field 'Blocks.BlockEntities'"); + for (BinaryTag entities : blockEntities) { + if (entities instanceof CompoundBinaryTag entity) { + BlockEntity blockEntity = BlockEntity.fromV3(entity); + System.out.println(blockEntity); + + Point coordinate = blockEntity.point(); + blockEntitiesMap.put(CoordinateUtil.getCoordinateKey(coordinate.blockX(), coordinate.blockY(), coordinate.blockZ()), blockEntity); + } + } + } else if(version == 2) { + palette = tag.getCompound("Palette"); + Check.notNull(palette, "Missing required field 'Palette'"); + blockArray = tag.getByteArray("BlockData"); + Check.notNull(blockArray, "Missing required field 'BlockData'"); + paletteSize = tag.getInt("PaletteMax"); + Check.notNull(paletteSize, "Missing required field 'PaletteMax'"); + ListBinaryTag blockEntities = tag.getList("BlockEntities"); + Check.notNull(blockEntities, "Missing required field 'BlockEntities'"); + for (BinaryTag entity : blockEntities) { + if (entity instanceof CompoundBinaryTag entityCompound) { + BlockEntity blockEntity = BlockEntity.fromV1(entityCompound); + System.out.println(blockEntity); + + Point coordinate = blockEntity.point(); + blockEntitiesMap.put(CoordinateUtil.getCoordinateKey(coordinate.blockX(), coordinate.blockY(), coordinate.blockZ()), blockEntity); + } + } } else { palette = tag.getCompound("Palette"); Check.notNull(palette, "Missing required field 'Palette'"); @@ -96,6 +134,17 @@ public SchematicReader withBlockPaletteParser(BlockPaletteParser parser) { Check.notNull(blockArray, "Missing required field 'BlockData'"); paletteSize = tag.getInt("PaletteMax"); Check.notNull(paletteSize, "Missing required field 'PaletteMax'"); + ListBinaryTag blockEntities = tag.getList("TileEntities"); + Check.notNull(blockEntities, "Missing required field 'TileEntities'"); + for (BinaryTag entity : blockEntities) { + if (entity instanceof CompoundBinaryTag entityCompound) { + BlockEntity blockEntity = BlockEntity.fromV1(entityCompound); + System.out.println(blockEntity); + + Point coordinate = blockEntity.point(); + blockEntitiesMap.put(CoordinateUtil.getCoordinateKey(coordinate.blockX(), coordinate.blockY(), coordinate.blockZ()), blockEntity); + } + } } Block[] paletteBlocks = new Block[paletteSize]; @@ -114,7 +163,8 @@ public SchematicReader withBlockPaletteParser(BlockPaletteParser parser) { new Vec(width, height, length), offset, paletteBlocks, - blockArray + blockArray, + blockEntitiesMap ); }