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 00000000..4119765f
Binary files /dev/null and b/src/test/resources/test.schematic differ