From 864a84b9b69b36eb85869a3c627e50d9d26ae065 Mon Sep 17 00:00:00 2001 From: Nanit Date: Mon, 24 Jan 2022 17:15:58 +0200 Subject: [PATCH] Added schematic containers and loader. Added world-related classes --- .../java/ru/nanit/limbo/LimboConstants.java | 1 + .../limbo/connection/ClientConnection.java | 2 +- .../protocol/packets/play/PacketJoinGame.java | 2 +- .../ru/nanit/limbo/server/LimboServer.java | 2 +- .../ru/nanit/limbo/server/data/Position.java | 92 ------------ .../java/ru/nanit/limbo/world/BlockData.java | 51 +++++++ .../ru/nanit/limbo/world/BlockEntity.java | 45 ++++++ .../java/ru/nanit/limbo/world/BlockMap.java | 34 +++++ .../java/ru/nanit/limbo/world/Location.java | 106 ++++++++++++++ .../world/{ => dimension}/Dimension.java | 2 +- .../{ => dimension}/DimensionRegistry.java | 2 +- .../limbo/world/schematic/Schematic.java | 40 ++++++ .../world/schematic/SchematicLoader.java | 132 +++++++++++++++++ .../schematic/versions/LegacySchematic.java | 133 ++++++++++++++++++ .../schematic/versions/SpongeSchematic.java | 103 ++++++++++++++ src/test/java/SchematicTest.java | 34 +++++ src/test/resources/test.schematic | Bin 0 -> 6981 bytes 17 files changed, 684 insertions(+), 97 deletions(-) delete mode 100644 src/main/java/ru/nanit/limbo/server/data/Position.java create mode 100644 src/main/java/ru/nanit/limbo/world/BlockData.java create mode 100644 src/main/java/ru/nanit/limbo/world/BlockEntity.java create mode 100644 src/main/java/ru/nanit/limbo/world/BlockMap.java create mode 100644 src/main/java/ru/nanit/limbo/world/Location.java rename src/main/java/ru/nanit/limbo/world/{ => dimension}/Dimension.java (96%) rename src/main/java/ru/nanit/limbo/world/{ => dimension}/DimensionRegistry.java (98%) create mode 100644 src/main/java/ru/nanit/limbo/world/schematic/Schematic.java create mode 100644 src/main/java/ru/nanit/limbo/world/schematic/SchematicLoader.java create mode 100644 src/main/java/ru/nanit/limbo/world/schematic/versions/LegacySchematic.java create mode 100644 src/main/java/ru/nanit/limbo/world/schematic/versions/SpongeSchematic.java create mode 100644 src/test/java/SchematicTest.java create mode 100644 src/test/resources/test.schematic diff --git a/src/main/java/ru/nanit/limbo/LimboConstants.java b/src/main/java/ru/nanit/limbo/LimboConstants.java index f5fddf5e..0c3d5b24 100644 --- a/src/main/java/ru/nanit/limbo/LimboConstants.java +++ b/src/main/java/ru/nanit/limbo/LimboConstants.java @@ -20,6 +20,7 @@ public final class LimboConstants { public static final String VELOCITY_INFO_CHANNEL = "velocity:player_info"; + public static final String BRAND_CHANNEL = "minecraft:brand"; private LimboConstants() {} diff --git a/src/main/java/ru/nanit/limbo/connection/ClientConnection.java b/src/main/java/ru/nanit/limbo/connection/ClientConnection.java index 8da4a32a..96a5c00e 100644 --- a/src/main/java/ru/nanit/limbo/connection/ClientConnection.java +++ b/src/main/java/ru/nanit/limbo/connection/ClientConnection.java @@ -434,7 +434,7 @@ public static void initPackets(LimboServer server) { if (server.getConfig().isUseBrandName()){ PacketPluginMessage pluginMessage = new PacketPluginMessage(); - pluginMessage.setChannel("minecraft:brand"); + pluginMessage.setChannel(LimboConstants.BRAND_CHANNEL); pluginMessage.setMessage(server.getConfig().getBrandName()); PACKET_PLUGIN_MESSAGE = PacketSnapshot.of(pluginMessage); } diff --git a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketJoinGame.java b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketJoinGame.java index 0043bc25..fdc33983 100644 --- a/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketJoinGame.java +++ b/src/main/java/ru/nanit/limbo/protocol/packets/play/PacketJoinGame.java @@ -20,7 +20,7 @@ import ru.nanit.limbo.protocol.ByteMessage; import ru.nanit.limbo.protocol.PacketOut; import ru.nanit.limbo.protocol.registry.Version; -import ru.nanit.limbo.world.DimensionRegistry; +import ru.nanit.limbo.world.dimension.DimensionRegistry; public class PacketJoinGame implements PacketOut { diff --git a/src/main/java/ru/nanit/limbo/server/LimboServer.java b/src/main/java/ru/nanit/limbo/server/LimboServer.java index 554a9232..bacbdae2 100644 --- a/src/main/java/ru/nanit/limbo/server/LimboServer.java +++ b/src/main/java/ru/nanit/limbo/server/LimboServer.java @@ -31,7 +31,7 @@ import ru.nanit.limbo.connection.ClientChannelInitializer; import ru.nanit.limbo.connection.ClientConnection; import ru.nanit.limbo.util.Logger; -import ru.nanit.limbo.world.DimensionRegistry; +import ru.nanit.limbo.world.dimension.DimensionRegistry; import java.nio.file.Paths; import java.util.concurrent.ScheduledFuture; diff --git a/src/main/java/ru/nanit/limbo/server/data/Position.java b/src/main/java/ru/nanit/limbo/server/data/Position.java deleted file mode 100644 index 9b6144ad..00000000 --- a/src/main/java/ru/nanit/limbo/server/data/Position.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2020 Nan1t - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package ru.nanit.limbo.server.data; - -import org.checkerframework.checker.nullness.qual.Nullable; -import org.spongepowered.configurate.ConfigurationNode; -import org.spongepowered.configurate.serialize.TypeSerializer; - -import java.lang.reflect.Type; - -public class Position { - - private double x; - private double y; - private double z; - private float yaw; - private float pitch; - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public double getZ() { - return z; - } - - public float getYaw() { - return yaw; - } - - public float getPitch() { - return pitch; - } - - public void setX(double x) { - this.x = x; - } - - public void setY(double y) { - this.y = y; - } - - public void setZ(double z) { - this.z = z; - } - - public void setYaw(float yaw) { - this.yaw = yaw; - } - - public void setPitch(float pitch) { - this.pitch = pitch; - } - - public static class Serializer implements TypeSerializer { - - @Override - public Position deserialize(Type type, ConfigurationNode node) { - Position position = new Position(); - position.setX(node.node("x").getDouble()); - position.setY(node.node("y").getDouble()); - position.setZ(node.node("z").getDouble()); - position.setYaw(node.node("yaw").getFloat()); - position.setPitch(node.node("pitch").getFloat()); - return position; - } - - @Override - public void serialize(Type type, @Nullable Position obj, ConfigurationNode node) { - - } - } -} diff --git a/src/main/java/ru/nanit/limbo/world/BlockData.java b/src/main/java/ru/nanit/limbo/world/BlockData.java new file mode 100644 index 00000000..9e8e03bb --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/BlockData.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world; + +public class BlockData { + + private final String state; + private final int id; + private final byte data; + + public BlockData(String state, int id, byte data) { + this.state = state; + this.id = id; + this.data = data; + } + + public BlockData(String state) { + this(state, 0, (byte) 0); + } + + public BlockData(int id, byte data) { + this(null, id, data); + } + + public String getState() { + return state; + } + + public int getId() { + return id; + } + + public byte getData() { + return data; + } +} diff --git a/src/main/java/ru/nanit/limbo/world/BlockEntity.java b/src/main/java/ru/nanit/limbo/world/BlockEntity.java new file mode 100644 index 00000000..01eeb4d2 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/BlockEntity.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world; + +import net.kyori.adventure.nbt.CompoundBinaryTag; + +public class BlockEntity { + + private final Location pos; + private final String id; + private final CompoundBinaryTag data; + + public BlockEntity(Location pos, String id, CompoundBinaryTag data) { + this.pos = pos; + this.id = id; + this.data = data; + } + + public Location getPos() { + return pos; + } + + public String getId() { + return id; + } + + public CompoundBinaryTag getData() { + return data; + } +} diff --git a/src/main/java/ru/nanit/limbo/world/BlockMap.java b/src/main/java/ru/nanit/limbo/world/BlockMap.java new file mode 100644 index 00000000..e69a9814 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/BlockMap.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world; + +import ru.nanit.limbo.protocol.registry.Version; + +public final class BlockMap { + + public BlockData convert(int id, byte data, Version version) { + // TODO + return null; + } + + public BlockData convert(String state, Version version) { + // TODO + return null; + } + +} diff --git a/src/main/java/ru/nanit/limbo/world/Location.java b/src/main/java/ru/nanit/limbo/world/Location.java new file mode 100644 index 00000000..53156094 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/Location.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.TypeSerializer; + +import java.lang.reflect.Type; + +public class Location { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + + Location(double x, double y, double z, float yaw, float pitch) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + } + + Location(double x, double y, double z) { + this(x, y, z, 0.0F, 0.0F); + } + + public double getX() { + return x; + } + + public int getBlockX() { + return (int) x; + } + + public double getY() { + return y; + } + + public int getBlockY() { + return (int) y; + } + + public double getZ() { + return z; + } + + public int getBlockZ() { + return (int) z; + } + + public float getYaw() { + return yaw; + } + + public float getPitch() { + return pitch; + } + + public static Location of(double x, double y, double z) { + return new Location(x, y, z); + } + + public static Location of(double x, double y, double z, float yaw, float pitch) { + return new Location(x, y, z, yaw, pitch); + } + + public static Location pos(int x, int y, int z) { + return new Location(x, y, z); + } + + public static class Serializer implements TypeSerializer { + + @Override + public Location deserialize(Type type, ConfigurationNode node) { + double x = node.node("x").getDouble(0); + double y = node.node("y").getDouble(0); + double z = node.node("z").getDouble(0); + float yaw = node.node("yaw").getFloat(0.0F); + float pitch = node.node("pitch").getFloat(0.0F); + + return new Location(x, y, z, yaw, pitch); + } + + @Override + public void serialize(Type type, @Nullable Location obj, ConfigurationNode node) { } + } +} diff --git a/src/main/java/ru/nanit/limbo/world/Dimension.java b/src/main/java/ru/nanit/limbo/world/dimension/Dimension.java similarity index 96% rename from src/main/java/ru/nanit/limbo/world/Dimension.java rename to src/main/java/ru/nanit/limbo/world/dimension/Dimension.java index 5b3c8156..4198688b 100644 --- a/src/main/java/ru/nanit/limbo/world/Dimension.java +++ b/src/main/java/ru/nanit/limbo/world/dimension/Dimension.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package ru.nanit.limbo.world; +package ru.nanit.limbo.world.dimension; import net.kyori.adventure.nbt.CompoundBinaryTag; diff --git a/src/main/java/ru/nanit/limbo/world/DimensionRegistry.java b/src/main/java/ru/nanit/limbo/world/dimension/DimensionRegistry.java similarity index 98% rename from src/main/java/ru/nanit/limbo/world/DimensionRegistry.java rename to src/main/java/ru/nanit/limbo/world/dimension/DimensionRegistry.java index 3479eee1..e4280324 100644 --- a/src/main/java/ru/nanit/limbo/world/DimensionRegistry.java +++ b/src/main/java/ru/nanit/limbo/world/dimension/DimensionRegistry.java @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package ru.nanit.limbo.world; +package ru.nanit.limbo.world.dimension; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.nbt.ListBinaryTag; diff --git a/src/main/java/ru/nanit/limbo/world/schematic/Schematic.java b/src/main/java/ru/nanit/limbo/world/schematic/Schematic.java new file mode 100644 index 00000000..548bbdf3 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/schematic/Schematic.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world.schematic; + +import ru.nanit.limbo.protocol.registry.Version; +import ru.nanit.limbo.world.BlockData; +import ru.nanit.limbo.world.BlockEntity; +import ru.nanit.limbo.world.BlockMap; +import ru.nanit.limbo.world.Location; + +import java.util.List; + +public interface Schematic { + + int getWidth(); + + int getHeight(); + + int getLength(); + + List getBlockEntities(); + + BlockData getBlock(Location loc, Version version, BlockMap mappings); + +} diff --git a/src/main/java/ru/nanit/limbo/world/schematic/SchematicLoader.java b/src/main/java/ru/nanit/limbo/world/schematic/SchematicLoader.java new file mode 100644 index 00000000..591f58fc --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/schematic/SchematicLoader.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world.schematic; + +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.BinaryTagIO; +import net.kyori.adventure.nbt.CompoundBinaryTag; +import ru.nanit.limbo.world.BlockEntity; +import ru.nanit.limbo.world.Location; +import ru.nanit.limbo.world.schematic.versions.LegacySchematic; +import ru.nanit.limbo.world.schematic.versions.SpongeSchematic; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class SchematicLoader { + + public Schematic load(Path file) throws IOException { + return load(Files.newInputStream(file)); + } + + public Schematic load(InputStream stream) throws IOException { + CompoundBinaryTag nbt = BinaryTagIO.unlimitedReader().read(stream, BinaryTagIO.Compression.GZIP); + + if (nbt.getCompound("BlockData") == CompoundBinaryTag.empty()) { + return loadLegacy(nbt); + } else { + return loadSponge(nbt); + } + } + + // Specification: https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-2.md + private Schematic loadSponge(CompoundBinaryTag nbt) { + SpongeSchematic schematic = new SpongeSchematic(); + + schematic.setDataVersion(nbt.getInt("DataVersion")); + + schematic.setWidth(nbt.getShort("Width")); + schematic.setHeight(nbt.getShort("Height")); + schematic.setLength(nbt.getShort("Length")); + + schematic.setPaletteMax(nbt.getInt("PaletteMax")); + + Map palette = new HashMap<>(); + CompoundBinaryTag paletteNbt = nbt.getCompound("Palette"); + + for (String key : paletteNbt.keySet()) { + palette.put(paletteNbt.getInt(key), key); + } + + schematic.setPalette(palette); + schematic.setBlockData(nbt.getByteArray("BlockData")); + + List blockEntities = new LinkedList<>(); + + for (BinaryTag tag : nbt.getList("BlockEntities")) { + if (tag instanceof CompoundBinaryTag) { + CompoundBinaryTag data = (CompoundBinaryTag) tag; + + int[] posArr = data.getIntArray("Pos"); + Location pos = Location.pos(posArr[0], posArr[1], posArr[2]); + String id = data.getString("Id"); + CompoundBinaryTag extra = data.getCompound("Extra"); + + blockEntities.add(new BlockEntity(pos, id, extra)); + } + } + + schematic.setBlockEntities(blockEntities); + + return schematic; + } + + private Schematic loadLegacy(CompoundBinaryTag nbt) { + LegacySchematic schematic = new LegacySchematic(); + + schematic.setWidth(nbt.getShort("Width")); + schematic.setHeight(nbt.getShort("Height")); + schematic.setLength(nbt.getShort("Length")); + + schematic.setMaterials(LegacySchematic.Materials.from(nbt.getString("Materials"))); + + schematic.setBlocks(nbt.getByteArray("Blocks")); + schematic.setAddBlocks(nbt.getByteArray("AddBlocks")); + schematic.setData(nbt.getByteArray("Data")); + + List blockEntities = new LinkedList<>(); + + for (BinaryTag tag : nbt.getList("TileEntities")) { + if (tag instanceof CompoundBinaryTag) { + CompoundBinaryTag data = (CompoundBinaryTag) tag; + + String id = data.getString("id"); + int x = data.getInt("x"); + int y = data.getInt("y"); + int z = data.getInt("z"); + + data.remove("id"); + data.remove("x"); + data.remove("y"); + data.remove("z"); + + blockEntities.add(new BlockEntity(Location.pos(x, y, z), id, data)); + } + } + + schematic.setBlockEntities(blockEntities); + + return schematic; + } +} diff --git a/src/main/java/ru/nanit/limbo/world/schematic/versions/LegacySchematic.java b/src/main/java/ru/nanit/limbo/world/schematic/versions/LegacySchematic.java new file mode 100644 index 00000000..9a35a8e3 --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/schematic/versions/LegacySchematic.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world.schematic.versions; + +import ru.nanit.limbo.protocol.registry.Version; +import ru.nanit.limbo.world.BlockData; +import ru.nanit.limbo.world.BlockEntity; +import ru.nanit.limbo.world.BlockMap; +import ru.nanit.limbo.world.Location; +import ru.nanit.limbo.world.schematic.Schematic; + +import java.util.List; + +/** + * Legacy schematic format (1.12-) + */ +public class LegacySchematic implements Schematic { + + private short width; + private short height; + private short length; + private Materials materials; + private byte[] blocks; + private byte[] addBlocks; + private byte[] data; + private List blockEntities; + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getLength() { + return length; + } + + @Override + public List getBlockEntities() { + return blockEntities; + } + + @Override + public BlockData getBlock(Location loc, Version version, BlockMap mappings) { + int index = (loc.getBlockY() * length + loc.getBlockZ()) * width + loc.getBlockX(); + byte id = this.blocks[index]; + byte data = this.data[index]; + + return mappings.convert(id, data, version); + } + + public void setWidth(short width) { + this.width = width; + } + + public void setHeight(short height) { + this.height = height; + } + + public void setLength(short length) { + this.length = length; + } + + public void setMaterials(Materials materials) { + this.materials = materials; + } + + public void setBlocks(byte[] blocks) { + this.blocks = blocks; + } + + public void setAddBlocks(byte[] addBlocks) { + this.addBlocks = addBlocks; + } + + public void setData(byte[] data) { + this.data = data; + } + + public void setBlockEntities(List blockEntities) { + this.blockEntities = blockEntities; + } + + @Override + public String toString() { + return "Schematic{" + + "width=" + width + + ", height=" + height + + ", length=" + length + + ", materials=" + materials + + ", blocks length=" + blocks.length + + ", addBlocks length=" + addBlocks.length + + ", data length=" + data.length + + ", blockEntities=" + blockEntities + + '}'; + } + + public enum Materials { + + CLASSIC, + ALPHA, + POCKET; + + public static Materials from(String value) { + switch (value.toLowerCase()) { + case "classic": return CLASSIC; + case "alpha": return ALPHA; + case "pocket": return POCKET; + default: throw new IllegalArgumentException("Invalid materials type"); + } + } + } +} diff --git a/src/main/java/ru/nanit/limbo/world/schematic/versions/SpongeSchematic.java b/src/main/java/ru/nanit/limbo/world/schematic/versions/SpongeSchematic.java new file mode 100644 index 00000000..5fc7b89b --- /dev/null +++ b/src/main/java/ru/nanit/limbo/world/schematic/versions/SpongeSchematic.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.nanit.limbo.world.schematic.versions; + +import ru.nanit.limbo.protocol.registry.Version; +import ru.nanit.limbo.world.BlockData; +import ru.nanit.limbo.world.BlockEntity; +import ru.nanit.limbo.world.BlockMap; +import ru.nanit.limbo.world.Location; +import ru.nanit.limbo.world.schematic.Schematic; + +import java.util.List; +import java.util.Map; + +/** + * Modern schematic format (Sponge second specification) + */ +public class SpongeSchematic implements Schematic { + + private int dataVersion; + private int width; + private int height; + private int length; + private int paletteMax; + private Map palette; + private byte[] blockData; + private List blockEntities; + + @Override + public int getWidth() { + return width; + } + + @Override + public int getHeight() { + return height; + } + + @Override + public int getLength() { + return length; + } + + @Override + public List getBlockEntities() { + return blockEntities; + } + + @Override + public BlockData getBlock(Location loc, Version version, BlockMap mappings) { + int index = loc.getBlockX() + loc.getBlockZ() * width + loc.getBlockY() * width * length; + int id = blockData[index]; + String state = palette.get(id); + return mappings.convert(state, version); + } + + public void setDataVersion(int dataVersion) { + this.dataVersion = dataVersion; + } + + public void setWidth(int width) { + this.width = width; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setLength(int length) { + this.length = length; + } + + public void setPaletteMax(int paletteMax) { + this.paletteMax = paletteMax; + } + + public void setPalette(Map palette) { + this.palette = palette; + } + + public void setBlockData(byte[] blockData) { + this.blockData = blockData; + } + + public void setBlockEntities(List blockEntities) { + this.blockEntities = blockEntities; + } +} diff --git a/src/test/java/SchematicTest.java b/src/test/java/SchematicTest.java new file mode 100644 index 00000000..a23a0540 --- /dev/null +++ b/src/test/java/SchematicTest.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 Nan1t + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import org.junit.jupiter.api.Test; +import ru.nanit.limbo.world.schematic.SchematicLoader; + +import java.io.IOException; +import java.io.InputStream; + +public class SchematicTest { + + @Test + public void testLoading() throws IOException { + SchematicLoader loader = new SchematicLoader(); + InputStream stream = getClass().getResourceAsStream("test.schematic"); + + System.out.println(loader.load(stream)); + } + +} diff --git a/src/test/resources/test.schematic b/src/test/resources/test.schematic new file mode 100644 index 0000000000000000000000000000000000000000..4119765f9bc9470c60feaa85ba08e6dff8b8df1d GIT binary patch literal 6981 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 literal 0 HcmV?d00001