diff --git a/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java b/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java index 47a813e..597663d 100644 --- a/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java @@ -2,17 +2,12 @@ package mc.protocol.packets.play.server; import io.netty.buffer.Unpooled; import lombok.Data; -import lombok.Getter; -import lombok.RequiredArgsConstructor; import mc.protocol.buffer.NetByteBuf; import mc.protocol.packets.ServerSidePacket; import mc.protocol.pool.ProtocolObjectPool; -import mc.protocol.world.Block; +import mc.protocol.utils.ChunkSerializeUtil; import mc.protocol.world.Chunk; import mc.protocol.world.ChunkSection; -import mc.utils.array.BitArray; -import mc.utils.array.BitByteArray; -import mc.utils.array.BitLongArray; /** * Данные чанка. @@ -79,9 +74,7 @@ import mc.utils.array.BitLongArray; @Data public class ChunkDataPacket implements ServerSidePacket { - private static final int BITS_PER_BLOCK = 13; private static final int FULL_BIT_MASK = 0b11111111_11111111; - private static final int _16_16_16 = 16 * 16 * 16; private Chunk chunk; @@ -90,12 +83,10 @@ public class ChunkDataPacket implements ServerSidePacket { netByteBuf.writeInt(chunk.getX()); // Chunk X netByteBuf.writeInt(chunk.getZ()); // Chunk Z - AvailableSections availableSections = createAvailableSections(); - boolean fullChunk = availableSections.getBitMask() == FULL_BIT_MASK; - netByteBuf.writeBoolean(fullChunk); // Is Full chunk - netByteBuf.writeVarInt(availableSections.getBitMask()); // Available Sections + netByteBuf.writeBoolean(true); // Is Full chunk + netByteBuf.writeVarInt(FULL_BIT_MASK); // Available Sections - NetByteBuf data = createDataStructure(availableSections.getMaxHeight(), fullChunk); + NetByteBuf data = createDataStructure(); netByteBuf.writeVarInt(data.readableBytes()); // Size of Data netByteBuf.writeBytes(data); // Data @@ -105,108 +96,26 @@ public class ChunkDataPacket implements ServerSidePacket { ProtocolObjectPool.getNetByteBufPool().returnObject(data); } - private AvailableSections createAvailableSections() { - int bitMask = 0; - int maxH = 0; - for (int h = 15; h >= 0; h--) { - bitMask = bitMask << 1; - ChunkSection chunkSection = chunk.getSection(h); - if (chunkSection != null && chunkSection.getY() == h) { - bitMask |= 0x01; - maxH++; - } else { - bitMask |= 0x00; - } - } - - return new AvailableSections(bitMask, maxH); - } - - private NetByteBuf createDataStructure(int maxHeight, boolean fillBiomes) { + private NetByteBuf createDataStructure() { NetByteBuf dataStructure = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()); - NetByteBuf biomes = fillBiomes ? ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()) : null; - for (int h = 0; h < maxHeight; h++) { + for (int h = 0; h < 16; h++) { ChunkSection section = chunk.getSection(h); - if (section == null) { - continue; - } - - NetByteBuf data = createData(section, biomes); + NetByteBuf data = ChunkSerializeUtil.serializeSection(section); dataStructure.writeBytes(data); // Data ProtocolObjectPool.getNetByteBufPool().returnObject(data); } - if (fillBiomes) { - dataStructure.writeBytes(biomes); // Biomes - ProtocolObjectPool.getNetByteBufPool().returnObject(biomes); + // + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + dataStructure.writeByte(chunk.getBiome( + (chunk.getX() << 4) + x, + (chunk.getZ() << 4) + z)); + } } + // return dataStructure; } - - private NetByteBuf createData(ChunkSection section, NetByteBuf biomes) { - NetByteBuf data = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()); - - BitArray blockLight = new BitByteArray(4, 2048 * 2); - BitArray skyLight = new BitByteArray(4, 2048 * 2); - - // - data.writeUnsignedByte(BITS_PER_BLOCK); - // - - // - data.writeVarInt(0); // Direct mode - // - - // - data.writeVarInt(_16_16_16); - // - - // - BitArray dataArray = new BitLongArray(BITS_PER_BLOCK, _16_16_16); - boolean writeBiomes = biomes != null; - - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - Block block = section.getBlock(x, y, z); - int blockState = (block.getId() << 4) | block.getMeta(); - dataArray.put(blockState); - - blockLight.put(block.getLight()); - skyLight.put(section.getSkyLight(x, y, z)); - - if (writeBiomes) { - biomes.writeByte(chunk.getBiome( - (chunk.getX() << 4) + x, - (chunk.getZ() << 4) + z)); - - if (x == 15 && z == 15) { - writeBiomes = false; - } - } - } - } - } - data.writeBytes(dataArray.byteBuffer()); - // - - // - data.writeBytes(blockLight.byteBuffer()); - // - - // - data.writeBytes(skyLight.byteBuffer()); - // - - return data; - } - - @RequiredArgsConstructor - @Getter - private static class AvailableSections { - private final int bitMask; - private final int maxHeight; - } } diff --git a/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java b/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java new file mode 100644 index 0000000..089a9b9 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/utils/ChunkSerializeUtil.java @@ -0,0 +1,48 @@ +package mc.protocol.utils; + +import io.netty.buffer.Unpooled; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import mc.protocol.buffer.NetByteBuf; +import mc.protocol.pool.ProtocolObjectPool; +import mc.protocol.world.Block; +import mc.protocol.world.ChunkSection; +import mc.utils.array.BitArray; +import mc.utils.array.BitByteArray; +import mc.utils.array.BitLongArray; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ChunkSerializeUtil { + + private static final int BITS_PER_BLOCK = 13; + private static final int ALL_BLOCKS = 16 * 16 * 16; + + public static NetByteBuf serializeSection(ChunkSection section) { + BitArray blockArray = new BitLongArray(BITS_PER_BLOCK, ALL_BLOCKS); + BitArray blockLight = new BitByteArray(4, ALL_BLOCKS); + BitArray skyLight = new BitByteArray(4, ALL_BLOCKS); + + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + Block block = section.getBlock(x, y, z); + int blockState = (block.getId() << 4) | block.getMeta(); + + blockArray.put(blockState); + blockLight.put(block.getLight()); + skyLight.put(section.getSkyLight(x, y, z)); + } + } + } + + NetByteBuf result = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()); + result.writeUnsignedByte(BITS_PER_BLOCK); // Bits Per Block + result.writeVarInt(0); // Palette, Direct mode + result.writeVarInt(blockArray.size()); // Data Array Length + result.writeBytes(blockArray.byteBuffer()); // Data Array + result.writeBytes(blockLight.byteBuffer()); // Block Light + result.writeBytes(skyLight.byteBuffer()); // Sky Light + + return result; + } +} diff --git a/server/src/main/java/mc/server/Main.java b/server/src/main/java/mc/server/Main.java index 22b1eb9..37651eb 100644 --- a/server/src/main/java/mc/server/Main.java +++ b/server/src/main/java/mc/server/Main.java @@ -67,7 +67,7 @@ public class Main { //endregion ServerComponent serverComponent = DaggerServerComponent.builder() - .processorModule(new ScenarioModule(configComponent.getConfig())) + .scenarioModule(new ScenarioModule(configComponent.getConfig())) .build(); serverComponent.getPacketScenarios().forEach(scenario -> scenario.setup(serverComponent.getProtocolHandlersBus())); diff --git a/server/src/main/java/mc/server/di/WorldModule.java b/server/src/main/java/mc/server/di/WorldModule.java index eedf194..4d6a03f 100644 --- a/server/src/main/java/mc/server/di/WorldModule.java +++ b/server/src/main/java/mc/server/di/WorldModule.java @@ -3,7 +3,7 @@ package mc.server.di; import dagger.Module; import dagger.Provides; import mc.protocol.world.World; -import mc.server.world.VoidWorld; +import mc.server.world.SomeWorld; import javax.inject.Singleton; @@ -13,6 +13,6 @@ public class WorldModule { @Provides @Singleton World provideWorld() { - return new VoidWorld(); + return new SomeWorld(); } } diff --git a/server/src/main/java/mc/server/scenario/ScenarioLogin.java b/server/src/main/java/mc/server/scenario/ScenarioLogin.java index c5f81ba..ee26aa4 100644 --- a/server/src/main/java/mc/server/scenario/ScenarioLogin.java +++ b/server/src/main/java/mc/server/scenario/ScenarioLogin.java @@ -37,7 +37,7 @@ public class ScenarioLogin implements PacketScenario { } private void login(ChannelHandlerContext ctx, LoginStartPacket packet) { - Player player = playerManager.create(ctx, packet.getName(), GameMode.SURVIVAL, world.getSpawn()); + Player player = playerManager.create(ctx, packet.getName(), GameMode.CREATIVE, world.getSpawn()); ctx.channel().attr(ServetAttributes.PLAYER).set(player); sendLoginSuccess(player); @@ -85,7 +85,7 @@ public class ScenarioLogin implements PacketScenario { var playerAbilitiesPacket = new PlayerAbilitiesPacket(); playerAbilitiesPacket.setCatFly(true); playerAbilitiesPacket.setFlying(true); - playerAbilitiesPacket.setCreativeMode(false); + playerAbilitiesPacket.setCreativeMode(true); playerAbilitiesPacket.setInvulnerable(true); playerAbilitiesPacket.setFieldOfView(0.0f); playerAbilitiesPacket.setFlyingSpeed(0.05f); @@ -96,7 +96,8 @@ public class ScenarioLogin implements PacketScenario { @SuppressWarnings("java:S2589") private void sendWorldData(Player player) { Location chunkLocation = LocationUtils.toChunkXZ(player.getLocation()); - Chunk chunk = world.getChunk((int) chunkLocation.getX(), (int) chunkLocation.getZ()); +// Chunk chunk = world.getChunk((int) chunkLocation.getX(), (int) chunkLocation.getZ()); + Chunk chunk = world.getChunk(-50, -16); var chunkDataPacket = new ChunkDataPacket(); chunkDataPacket.setChunk(chunk); @@ -112,8 +113,11 @@ public class ScenarioLogin implements PacketScenario { for (int x = minX; x <= maxX; x++) { if ((z == minZ || z == maxZ) || (x == minX || x == maxX)) { chunkDataPacket = new ChunkDataPacket(); - chunkDataPacket.setChunk(world.getChunk(x, z)); - player.getCtx().write(chunkDataPacket); + chunk = world.getChunk(x, z); + if (chunk != null) { + chunkDataPacket.setChunk(chunk); + player.getCtx().write(chunkDataPacket); + } } } } diff --git a/server/src/main/java/mc/server/world/AirBlock.java b/server/src/main/java/mc/server/world/AirBlock.java deleted file mode 100644 index 1bb6dd7..0000000 --- a/server/src/main/java/mc/server/world/AirBlock.java +++ /dev/null @@ -1,33 +0,0 @@ -package mc.server.world; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import mc.protocol.model.Location; -import mc.protocol.world.Block; - -@RequiredArgsConstructor -public class AirBlock implements Block { - - @Getter - private final Location location; - - @Override - public int getId() { - return 0; - } - - @Override - public int getMeta() { - return 0; - } - - @Override - public int getLight() { - return 0; - } - - @Override - public void setLight(int value) { - throw new UnsupportedOperationException(); - } -} diff --git a/server/src/main/java/mc/server/world/SomeBlock.java b/server/src/main/java/mc/server/world/SomeBlock.java new file mode 100644 index 0000000..4c282a3 --- /dev/null +++ b/server/src/main/java/mc/server/world/SomeBlock.java @@ -0,0 +1,14 @@ +package mc.server.world; + +import lombok.Data; +import mc.protocol.model.Location; +import mc.protocol.world.Block; + +@Data +public class SomeBlock implements Block { + + private int id; + private int meta; + private int light; + private Location location; +} diff --git a/server/src/main/java/mc/server/world/VoidChunk.java b/server/src/main/java/mc/server/world/SomeChunk.java similarity index 58% rename from server/src/main/java/mc/server/world/VoidChunk.java rename to server/src/main/java/mc/server/world/SomeChunk.java index 303ecc6..544bf0d 100644 --- a/server/src/main/java/mc/server/world/VoidChunk.java +++ b/server/src/main/java/mc/server/world/SomeChunk.java @@ -8,19 +8,19 @@ import java.util.HashMap; import java.util.Map; @Data -public class VoidChunk implements Chunk { +public class SomeChunk implements Chunk { private final int x; private final int z; - private final Map sections = new HashMap<>(); + private final Map sections = new HashMap<>(); @Override public ChunkSection getSection(int height) { - return sections.computeIfAbsent(height, VoidChunkSection::new); + return sections.computeIfAbsent(height, SomeChunkSection::new); } @Override public byte getBiome(int x, int z) { - return 127; // 127 | 7F | minecraft:void | The Void + return 0; //ocean } } diff --git a/server/src/main/java/mc/server/world/SomeChunkSection.java b/server/src/main/java/mc/server/world/SomeChunkSection.java new file mode 100644 index 0000000..d090af6 --- /dev/null +++ b/server/src/main/java/mc/server/world/SomeChunkSection.java @@ -0,0 +1,56 @@ +package mc.server.world; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.protocol.model.Location; +import mc.protocol.world.Block; +import mc.protocol.world.ChunkSection; + +import java.util.HashMap; +import java.util.Map; + +@RequiredArgsConstructor +@Getter +public class SomeChunkSection implements ChunkSection { + + private final int y; + private final Map blocks = new HashMap<>(); + + @Override + public Block getBlock(int x, int y, int z) { + if (this.y == 15) { + if (y == 0) { + return blocks.computeIfAbsent(new Location().set(x, y, z), location -> { + SomeBlock block = new SomeBlock(); + block.setLocation(location); + block.setId(3); + return block; + }); + } else { + return blocks.computeIfAbsent(new Location().set(x, y, z), location -> { + SomeBlock block = new SomeBlock(); + block.setLocation(location); + block.setId(0); + return block; + }); + } + } else { + return blocks.computeIfAbsent(new Location().set(x, y, z), location -> { + SomeBlock block = new SomeBlock(); + block.setLocation(location); + block.setId(1); + return block; + }); + } + } + + @Override + public int getSkyLight(int x, int y, int z) { + if (this.y == 15 && y != 0) { + return 15; + } else { + return 0; + } + } + +} \ No newline at end of file diff --git a/server/src/main/java/mc/server/world/VoidWorld.java b/server/src/main/java/mc/server/world/SomeWorld.java similarity index 59% rename from server/src/main/java/mc/server/world/VoidWorld.java rename to server/src/main/java/mc/server/world/SomeWorld.java index 5bdffd4..c7368de 100644 --- a/server/src/main/java/mc/server/world/VoidWorld.java +++ b/server/src/main/java/mc/server/world/SomeWorld.java @@ -3,14 +3,14 @@ package mc.server.world; import mc.protocol.model.Location; import mc.protocol.pool.ProtocolObjectPool; import mc.protocol.utils.LevelType; -import mc.protocol.utils.Table; import mc.protocol.world.Chunk; import mc.protocol.world.World; +import mc.utils.Table; -public class VoidWorld implements World { +public class SomeWorld implements World { - private static final Location spawn = ProtocolObjectPool.getLocationPool().borrowObject().set(7d, 130d, 7d); - private final Table chunkTable = new Table<>(); + private static final Location spawn = ProtocolObjectPool.getLocationPool().borrowObject().set(-790d, 256d, -263d + 16d); + private final Table chunkTable = new Table<>(); @Override public LevelType getLevelType() { @@ -19,14 +19,18 @@ public class VoidWorld implements World { @Override public Location getSpawn() { - return VoidWorld.spawn; + return SomeWorld.spawn; } @Override public Chunk getChunk(int x, int z) { - VoidChunk chunk = chunkTable.getColumnAndRow(x, z); + if (x != -50 && z != -16) { + return null; + } + + Chunk chunk = chunkTable.getColumnAndRow(x, z); if (chunk == null) { - chunk = new VoidChunk(x, z); + chunk = new SomeChunk(x, z); chunkTable.put(x, z, chunk); } diff --git a/server/src/main/java/mc/server/world/VoidChunkSection.java b/server/src/main/java/mc/server/world/VoidChunkSection.java deleted file mode 100644 index bc0cdf2..0000000 --- a/server/src/main/java/mc/server/world/VoidChunkSection.java +++ /dev/null @@ -1,29 +0,0 @@ -package mc.server.world; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import mc.protocol.model.Location; -import mc.protocol.world.Block; -import mc.protocol.world.ChunkSection; - -import java.util.HashMap; -import java.util.Map; - -@RequiredArgsConstructor -@Getter -public class VoidChunkSection implements ChunkSection { - - private final int y; - private final Map blocks = new HashMap<>(); - - @Override - public Block getBlock(int x, int y, int z) { - return blocks.computeIfAbsent(new Location().set(x, y, z), AirBlock::new); - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - -} \ No newline at end of file diff --git a/server/src/main/resources/config-default.conf b/server/src/main/resources/config-default.conf index 5a91e83..0dd6f63 100644 --- a/server/src/main/resources/config-default.conf +++ b/server/src/main/resources/config-default.conf @@ -23,5 +23,5 @@ icon { } world { - view-distance: 1 + view-distance: 0 } diff --git a/server/src/main/resources/logback-default.xml b/server/src/main/resources/logback-default.xml index a8d8e6f..fde6ed4 100644 --- a/server/src/main/resources/logback-default.xml +++ b/server/src/main/resources/logback-default.xml @@ -8,8 +8,16 @@ + + + diff --git a/utils/src/main/java/mc/utils/array/BitArray.java b/utils/src/main/java/mc/utils/array/BitArray.java index d784f7d..c58c495 100644 --- a/utils/src/main/java/mc/utils/array/BitArray.java +++ b/utils/src/main/java/mc/utils/array/BitArray.java @@ -10,4 +10,5 @@ public interface BitArray { int get(int index); ByteBuffer byteBuffer(); + int size(); } diff --git a/utils/src/main/java/mc/utils/array/BitByteArray.java b/utils/src/main/java/mc/utils/array/BitByteArray.java index 29b4987..a871975 100644 --- a/utils/src/main/java/mc/utils/array/BitByteArray.java +++ b/utils/src/main/java/mc/utils/array/BitByteArray.java @@ -2,6 +2,8 @@ package mc.utils.array; public class BitByteArray extends AbstractBitBufferArray { + private int countElements; + public BitByteArray(int bitPerEntity, int arraySize, boolean direct) { super(bitPerEntity, arraySize, direct); } @@ -55,8 +57,16 @@ public class BitByteArray extends AbstractBitBufferArray { } } + @Override + public int size() { + return countElements; + } + @Override protected int calculateCapacity() { - return (arraySize * bitPerEntity / Byte.SIZE + 1) * Byte.BYTES; + int bits = arraySize * bitPerEntity; + int var1 = bits % Byte.SIZE; + this.countElements = bits / Byte.SIZE + (var1 > 0 ? 1 : 0); + return countElements; } } diff --git a/utils/src/main/java/mc/utils/array/BitLongArray.java b/utils/src/main/java/mc/utils/array/BitLongArray.java index ac75ca8..0af7b94 100644 --- a/utils/src/main/java/mc/utils/array/BitLongArray.java +++ b/utils/src/main/java/mc/utils/array/BitLongArray.java @@ -5,6 +5,7 @@ import java.nio.LongBuffer; public class BitLongArray extends AbstractBitBufferArray { private final LongBuffer longBuffer; + private int countElements; public BitLongArray(int bitPerEntity, int arraySize, boolean direct) { super(bitPerEntity, arraySize, direct); @@ -60,8 +61,17 @@ public class BitLongArray extends AbstractBitBufferArray { } } + @Override + public int size() { + return countElements; + } + @Override protected int calculateCapacity() { - return (arraySize * bitPerEntity / Long.SIZE + 1) * Long.BYTES; + int bits = arraySize * bitPerEntity; + int var1 = bits % Long.SIZE; + int var2 = (bits + (var1 > 0 ? Long.SIZE - var1 : 0)); + this.countElements = var2 / Long.SIZE; + return var2 / Byte.SIZE; } } diff --git a/utils/src/test/java/mc/utils/array/BitByteArrayTest.java b/utils/src/test/java/mc/utils/array/BitByteArrayTest.java index d1bfb02..9a912ad 100644 --- a/utils/src/test/java/mc/utils/array/BitByteArrayTest.java +++ b/utils/src/test/java/mc/utils/array/BitByteArrayTest.java @@ -17,12 +17,21 @@ class BitByteArrayTest { assertEquals(1, byteBuffer.limit()); assertEquals(0, byteBuffer.position()); assertEquals(1, byteBuffer.array().length); + assertEquals(1, bitArray.size()); bitArray = new BitByteArray(4, 2); byteBuffer = bitArray.byteBuffer(); + assertEquals(1, byteBuffer.capacity()); + assertEquals(1, byteBuffer.limit()); + assertEquals(1, bitArray.size()); + + bitArray = new BitByteArray(4, 3); + byteBuffer = bitArray.byteBuffer(); + assertEquals(2, byteBuffer.capacity()); assertEquals(2, byteBuffer.limit()); + assertEquals(2, bitArray.size()); } @Test diff --git a/utils/src/test/java/mc/utils/array/BitLongArrayTest.java b/utils/src/test/java/mc/utils/array/BitLongArrayTest.java index 04717bc..2a66143 100644 --- a/utils/src/test/java/mc/utils/array/BitLongArrayTest.java +++ b/utils/src/test/java/mc/utils/array/BitLongArrayTest.java @@ -18,12 +18,14 @@ class BitLongArrayTest { assertEquals(8, byteBuffer.limit()); assertEquals(0, byteBuffer.position()); assertEquals(8, byteBuffer.array().length); + assertEquals(1, bitArray.size()); bitArray = new BitLongArray(13, 5); byteBuffer = bitArray.byteBuffer(); assertEquals(16, byteBuffer.capacity()); assertEquals(16, byteBuffer.limit()); + assertEquals(2, bitArray.size()); } @Test