Added schematic containers and loader. Added world-related classes

This commit is contained in:
Nanit 2022-01-24 17:15:58 +02:00
parent 9f3fa80eef
commit 864a84b9b6
17 changed files with 684 additions and 97 deletions

View File

@ -20,6 +20,7 @@ package ru.nanit.limbo;
public final class LimboConstants {
public static final String VELOCITY_INFO_CHANNEL = "velocity:player_info";
public static final String BRAND_CHANNEL = "minecraft:brand";
private LimboConstants() {}

View File

@ -434,7 +434,7 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
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);
}

View File

@ -20,7 +20,7 @@ package ru.nanit.limbo.protocol.packets.play;
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 {

View File

@ -31,7 +31,7 @@ import ru.nanit.limbo.configuration.LimboConfig;
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;

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Position> {
@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) {
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Location> {
@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) { }
}
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.nanit.limbo.world;
package ru.nanit.limbo.world.dimension;
import net.kyori.adventure.nbt.CompoundBinaryTag;

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.nanit.limbo.world;
package ru.nanit.limbo.world.dimension;
import net.kyori.adventure.nbt.CompoundBinaryTag;
import net.kyori.adventure.nbt.ListBinaryTag;

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<BlockEntity> getBlockEntities();
BlockData getBlock(Location loc, Version version, BlockMap mappings);
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Integer, String> 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<BlockEntity> 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<BlockEntity> 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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<BlockEntity> blockEntities;
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public int getLength() {
return length;
}
@Override
public List<BlockEntity> 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<BlockEntity> 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");
}
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Integer, String> palette;
private byte[] blockData;
private List<BlockEntity> blockEntities;
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
@Override
public int getLength() {
return length;
}
@Override
public List<BlockEntity> 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<Integer, String> palette) {
this.palette = palette;
}
public void setBlockData(byte[] blockData) {
this.blockData = blockData;
}
public void setBlockEntities(List<BlockEntity> blockEntities) {
this.blockEntities = blockEntities;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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));
}
}

Binary file not shown.