diff --git a/protocol/src/main/java/mc/protocol/model/Location.java b/protocol/src/main/java/mc/protocol/model/Location.java index 697f64b..483db15 100644 --- a/protocol/src/main/java/mc/protocol/model/Location.java +++ b/protocol/src/main/java/mc/protocol/model/Location.java @@ -9,4 +9,16 @@ public class Location { private double x; private double y; private double z; + + public int getIntX() { + return (int) x; + } + + public int getIntZ() { + return (int) z; + } + + public Location toChunkXZ() { + return new Location(this.getIntX() >> 4, 0d, this.getIntZ() >> 4); + } } diff --git a/protocol/src/main/java/mc/protocol/packets/server/ChunkDataPacket.java b/protocol/src/main/java/mc/protocol/packets/server/ChunkDataPacket.java index ca0eba2..cfcac8d 100644 --- a/protocol/src/main/java/mc/protocol/packets/server/ChunkDataPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/server/ChunkDataPacket.java @@ -28,13 +28,17 @@ import mc.protocol.packets.ServerSidePacket; @Data public class ChunkDataPacket implements ServerSidePacket { + private static NetByteBuf voidData; + private int x; private int z; + @SuppressWarnings("java:S125") @Override public void writeSelf(NetByteBuf netByteBuf) { netByteBuf.writeInt(x); netByteBuf.writeInt(z); + /* Временное отключение кода netByteBuf.writeBoolean(true); // Is Full chunk netByteBuf.writeVarInt(0b11111111); // Available Sections @@ -64,6 +68,41 @@ public class ChunkDataPacket implements ServerSidePacket { netByteBuf.writeVarInt(data.readableBytes()); // Size of Data netByteBuf.writeBytes(data); // Data netByteBuf.writeVarInt(0); // Number of block entities - /* write NBT's */ + // write NBT's + */ + + netByteBuf.writeBytes(voidData); + + voidData.resetReaderIndex(); + voidData.resetWriterIndex(); + } + + static { + voidData = new NetByteBuf(Unpooled.buffer()); + voidData.writeBoolean(true); // Is Full chunk + voidData.writeVarInt(0b11111111); // Available Sections + + NetByteBuf data = new NetByteBuf(Unpooled.buffer()); + for (int i = 0; i < 16; i++) { + NetByteBuf dataBuff = new NetByteBuf(Unpooled.wrappedBuffer(new byte[4096])); + NetByteBuf blockLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048])); + NetByteBuf skyLight = new NetByteBuf(Unpooled.wrappedBuffer(new byte[2048])); + NetByteBuf biomes = new NetByteBuf(Unpooled.wrappedBuffer(new byte[256])); + + data.writeUnsignedByte(13); + data.writeUnsignedByte(0); + data.writeVarInt(dataBuff.readableBytes()); + data.writeBytes(dataBuff); + data.writeBytes(blockLight); + data.writeBytes(skyLight); + data.writeBytes(biomes); + } + + voidData.writeVarInt(data.readableBytes()); + voidData.writeBytes(data); + voidData.writeVarInt(0); + + voidData.markReaderIndex(); + voidData.markWriterIndex(); } } diff --git a/protocol/src/main/java/mc/protocol/world/Chunk.java b/protocol/src/main/java/mc/protocol/world/Chunk.java new file mode 100644 index 0000000..ec4a551 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/world/Chunk.java @@ -0,0 +1,7 @@ +package mc.protocol.world; + +public interface Chunk { + + int getX(); + int getZ(); +} diff --git a/protocol/src/main/java/mc/protocol/world/World.java b/protocol/src/main/java/mc/protocol/world/World.java new file mode 100644 index 0000000..1d57700 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/world/World.java @@ -0,0 +1,13 @@ +package mc.protocol.world; + +import mc.protocol.model.Location; +import mc.protocol.utils.LevelType; + +public interface World { + + LevelType getLevelType(); + + Location getSpawn(); + + Chunk getChunk(int x, int z); +} diff --git a/server/src/main/java/mc/server/PacketHandler.java b/server/src/main/java/mc/server/PacketHandler.java index 8a97201..11ae54f 100644 --- a/server/src/main/java/mc/server/PacketHandler.java +++ b/server/src/main/java/mc/server/PacketHandler.java @@ -15,7 +15,8 @@ import mc.protocol.packets.server.*; import mc.protocol.serializer.TextSerializer; import mc.protocol.utils.Difficulty; import mc.protocol.utils.GameMode; -import mc.protocol.utils.LevelType; +import mc.protocol.world.Chunk; +import mc.protocol.world.World; import mc.server.config.Config; import org.apache.commons.io.IOUtils; @@ -34,6 +35,7 @@ public class PacketHandler { private final Random random = new Random(System.currentTimeMillis()); private final Config config; + private final World world; public void onHandshake(ConnectionContext context, HandshakePacket packet) { context.setState(packet.getNextState()); @@ -75,6 +77,7 @@ public class PacketHandler { context.sendNow(response); } + @SuppressWarnings("java:S2589") public void onLoginStart(ConnectionContext context, LoginStartPacket loginStartPacket) { var loginSuccessPacket = new LoginSuccessPacket(); loginSuccessPacket.setUuid(UUID.randomUUID()); @@ -88,14 +91,12 @@ public class PacketHandler { joinGamePacket.setGameMode(GameMode.SURVIVAL); joinGamePacket.setDimension(0/*Overworld*/); joinGamePacket.setDifficulty(Difficulty.PEACEFUL); - joinGamePacket.setLevelType(LevelType.FLAT); + joinGamePacket.setLevelType(world.getLevelType()); context.send(joinGamePacket); - Location spawnLocation = new Location(7d, 130d, 7d); - var spawnPositionPacket = new SpawnPositionPacket(); - spawnPositionPacket.setSpawn(spawnLocation); + spawnPositionPacket.setSpawn(world.getSpawn()); context.send(spawnPositionPacket); @@ -111,14 +112,38 @@ public class PacketHandler { context.flushSending(); - var chunkDataPacket = new ChunkDataPacket(); - chunkDataPacket.setX(0); - chunkDataPacket.setZ(0); + Location chunkLocation = world.getSpawn().toChunkXZ(); + Chunk chunk = world.getChunk(chunkLocation.getIntX(), chunkLocation.getIntZ()); - context.sendNow(chunkDataPacket); + var chunkDataPacket = new ChunkDataPacket(); + chunkDataPacket.setX(chunk.getX()); + chunkDataPacket.setZ(chunk.getZ()); + + context.send(chunkDataPacket); + + for (int i = 1; i <= config.world().viewDistance(); i++) { + int minX = chunkLocation.getIntX() - i; + int minZ = chunkLocation.getIntZ() - i; + int maxX = chunkLocation.getIntX() + i; + int maxZ = chunkLocation.getIntZ() + i; + + for (int z = minZ; z <= maxZ; z++) { + for (int x = minX; x <= maxX; x++) { + if ((z == minZ || z == maxZ) || (x == minX || x == maxX)) { + chunkDataPacket = new ChunkDataPacket(); + chunkDataPacket.setX(x); + chunkDataPacket.setZ(z); + + context.send(chunkDataPacket); + } + } + } + } + + context.flushSending(); var playerPositionAndLookPacket = new SPlayerPositionAndLookPacket(); - playerPositionAndLookPacket.setPosition(spawnLocation); + playerPositionAndLookPacket.setPosition(world.getSpawn()); playerPositionAndLookPacket.setLook(new Look(0f, 0f)); playerPositionAndLookPacket.setTeleportId(random.nextInt()); diff --git a/server/src/main/java/mc/server/config/Config.java b/server/src/main/java/mc/server/config/Config.java index 07340fc..5d99eb4 100644 --- a/server/src/main/java/mc/server/config/Config.java +++ b/server/src/main/java/mc/server/config/Config.java @@ -15,6 +15,7 @@ public class Config { private final Server server = new Server(); private final Players players = new Players(); + private final World world = new World(); private String motd; private String disconnectReason; @@ -35,4 +36,11 @@ public class Config { private int maxOnlile; private int onlile; } + + @Getter + @Setter + @ToString + public static class World { + private int viewDistance; + } } diff --git a/server/src/main/java/mc/server/di/ConfigModule.java b/server/src/main/java/mc/server/di/ConfigModule.java index c4bd5b0..12bb65f 100644 --- a/server/src/main/java/mc/server/di/ConfigModule.java +++ b/server/src/main/java/mc/server/di/ConfigModule.java @@ -31,6 +31,7 @@ public class ConfigModule { config.disconnectReason(fromYamlPath("disconnect-reason", map, "")); config.players().maxOnlile(fromYamlPath("players/max-online", map, 0)); config.players().onlile(fromYamlPath("players/online", map, 0)); + config.world().viewDistance(fromYamlPath("world/view-distance", map, 0)); if (Boolean.TRUE.equals(fromYamlPath("icon/enable", map, false))) { config.iconPath(Paths.get(fromYamlPath("icon/path", map, "favicon.png"))); diff --git a/server/src/main/java/mc/server/di/PacketHandlerModule.java b/server/src/main/java/mc/server/di/PacketHandlerModule.java index d90f3a7..750652c 100644 --- a/server/src/main/java/mc/server/di/PacketHandlerModule.java +++ b/server/src/main/java/mc/server/di/PacketHandlerModule.java @@ -2,6 +2,7 @@ package mc.server.di; import dagger.Module; import dagger.Provides; +import mc.protocol.world.World; import mc.server.PacketHandler; import mc.server.config.Config; @@ -9,7 +10,7 @@ import mc.server.config.Config; public class PacketHandlerModule { @Provides - public PacketHandler providePacketHandler(Config config) { - return new PacketHandler(config); + public PacketHandler providePacketHandler(Config config, World world) { + return new PacketHandler(config, world); } } diff --git a/server/src/main/java/mc/server/di/ServerComponent.java b/server/src/main/java/mc/server/di/ServerComponent.java index 9b7ec2e..ad89a4d 100644 --- a/server/src/main/java/mc/server/di/ServerComponent.java +++ b/server/src/main/java/mc/server/di/ServerComponent.java @@ -1,12 +1,14 @@ package mc.server.di; import dagger.Component; +import mc.protocol.di.ServerScope; import mc.server.PacketHandler; import mc.server.config.Config; @Component(modules = { - ConfigModule.class, PacketHandlerModule.class + ConfigModule.class, PacketHandlerModule.class, WorldModule.class }) +@ServerScope public interface ServerComponent { Config getConfig(); diff --git a/server/src/main/java/mc/server/di/WorldModule.java b/server/src/main/java/mc/server/di/WorldModule.java new file mode 100644 index 0000000..b2ecf19 --- /dev/null +++ b/server/src/main/java/mc/server/di/WorldModule.java @@ -0,0 +1,17 @@ +package mc.server.di; + +import dagger.Module; +import dagger.Provides; +import mc.protocol.di.ServerScope; +import mc.protocol.world.World; +import mc.server.world.VoidWorld; + +@Module +public class WorldModule { + + @Provides + @ServerScope + public World provideWorld() { + return new VoidWorld(); + } +} diff --git a/server/src/main/java/mc/server/world/VoidChunk.java b/server/src/main/java/mc/server/world/VoidChunk.java new file mode 100644 index 0000000..3ee5cb6 --- /dev/null +++ b/server/src/main/java/mc/server/world/VoidChunk.java @@ -0,0 +1,13 @@ +package mc.server.world; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.world.Chunk; + +@RequiredArgsConstructor +@Getter +public class VoidChunk implements Chunk { + + private final int x; + private final int z; +} diff --git a/server/src/main/java/mc/server/world/VoidWorld.java b/server/src/main/java/mc/server/world/VoidWorld.java new file mode 100644 index 0000000..a2df89b --- /dev/null +++ b/server/src/main/java/mc/server/world/VoidWorld.java @@ -0,0 +1,26 @@ +package mc.server.world; + +import mc.protocol.model.Location; +import mc.protocol.utils.LevelType; +import mc.protocol.world.Chunk; +import mc.protocol.world.World; + +public class VoidWorld implements World { + + private static final Location spawn = new Location(7d, 130d, 7d); + + @Override + public LevelType getLevelType() { + return LevelType.FLAT; + } + + @Override + public Location getSpawn() { + return VoidWorld.spawn; + } + + @Override + public Chunk getChunk(int x, int z) { + return new VoidChunk(x, z); + } +} diff --git a/server/src/main/resources/config-sample.yml b/server/src/main/resources/config-sample.yml index c26428c..d96b359 100644 --- a/server/src/main/resources/config-sample.yml +++ b/server/src/main/resources/config-sample.yml @@ -15,4 +15,7 @@ players: # Размер значка: 64x64 px icon: enable: false - path: favicon.png \ No newline at end of file + path: favicon.png + +world: + view-distance: 1 \ No newline at end of file