diff --git a/protocol/src/main/java/mc/protocol/Difficulty.java b/protocol/src/main/java/mc/protocol/Difficulty.java new file mode 100644 index 0000000..def20c1 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/Difficulty.java @@ -0,0 +1,15 @@ +package mc.protocol; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum Difficulty { + PEACEFUL(0), + EASY(1), + NORMAL(2), + HARD(3); + + private final int id; +} diff --git a/protocol/src/main/java/mc/protocol/GameMode.java b/protocol/src/main/java/mc/protocol/GameMode.java new file mode 100644 index 0000000..b224ea6 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/GameMode.java @@ -0,0 +1,15 @@ +package mc.protocol; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum GameMode { + SURVIVAL(0), + CREATIVE(1), + ADVENTURE(2), + SPECTATOR(3); + + private final int id; +} diff --git a/protocol/src/main/java/mc/protocol/LevelType.java b/protocol/src/main/java/mc/protocol/LevelType.java new file mode 100644 index 0000000..2b99f36 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/LevelType.java @@ -0,0 +1,16 @@ +package mc.protocol; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum LevelType { + DEFAULT_TYPE("default"), + FLAT("flat"), + LARGE_BIOMES("largeBiomes"), + AMPLIFIED("amplified"), + DEFAULT_1_1("default_1_1"); + + private final String type; +} diff --git a/protocol/src/main/java/mc/protocol/State.java b/protocol/src/main/java/mc/protocol/State.java index 98e929e..a4227dd 100644 --- a/protocol/src/main/java/mc/protocol/State.java +++ b/protocol/src/main/java/mc/protocol/State.java @@ -10,6 +10,7 @@ import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequestPacket; import mc.protocol.packets.server.DisconnectPacket; +import mc.protocol.packets.server.JoinGamePacket; import mc.protocol.packets.server.LoginSuccessPacket; import mc.protocol.packets.server.StatusServerResponse; @@ -44,6 +45,12 @@ public enum State { DisconnectPacket.class, 0x00, LoginSuccessPacket.class, 0x02 ) + ), + PLAY(3, + // server bound + Map.of(), + // client bound + Map.of(JoinGamePacket.class, 0x23) ); @Nullable diff --git a/protocol/src/main/java/mc/protocol/io/NetByteBuf.java b/protocol/src/main/java/mc/protocol/io/NetByteBuf.java index da59f07..1b038e8 100644 --- a/protocol/src/main/java/mc/protocol/io/NetByteBuf.java +++ b/protocol/src/main/java/mc/protocol/io/NetByteBuf.java @@ -49,6 +49,10 @@ public class NetByteBuf extends ByteBuf { @Delegate private final ByteBuf byteBuf; + public void writeUnsignedByte(int value) { + byteBuf.writeByte((byte)(value & 0xFF)); + } + //region String public String readString() { return readString(Short.MAX_VALUE); diff --git a/protocol/src/main/java/mc/protocol/packets/server/JoinGamePacket.java b/protocol/src/main/java/mc/protocol/packets/server/JoinGamePacket.java new file mode 100644 index 0000000..936bc82 --- /dev/null +++ b/protocol/src/main/java/mc/protocol/packets/server/JoinGamePacket.java @@ -0,0 +1,59 @@ +package mc.protocol.packets.server; + +import lombok.Data; +import mc.protocol.Difficulty; +import mc.protocol.GameMode; +import mc.protocol.LevelType; +import mc.protocol.io.NetByteBuf; +import mc.protocol.packets.ServerSidePacket; + +/** + * Join game packet. + * + *
Структура пакета
+ *+ * | FIELD | TYPE | NOTES | + * |--------------------|---------------|----------------------------------------------------------------------| + * | Entity ID | Integer | ID сущности (игрока) | + * | Gamemode | Unsigned Byte | 0: Survival | + * | | | 1: Creative | + * | | | 2: Adventure | + * | | | 3: Spectator | + * | | | Bit 3 (0x8) is the hardcore flag. | + * | Dimension | Integer | -1: Nether | + * | | | 0: Overworld | + * | | | 1: End | + * | Difficulty | Unsigned Byte | 0: peaceful | + * | | | 1: easy | + * | | | 2: normal | + * | | | 3: hard | + * | Max Players | Unsigned Byte | Когда-то использовался клиентом для | + * | | | отображения списка игроков. Теперь не используется | + * | Level Type | String (16) | Принимает одно из значений: | + * | | | default, flat, largeBiomes, amplified, default_1_1 | + * | Reduced Debug Info | Boolean | Если true, то Клиент отображает меньше отладочной информации (в F3?) | + *+ * + * @see Join Game + */ +@Data +public class JoinGamePacket implements ServerSidePacket { + + private int entityId; + private GameMode gameMode; + private int dimension; + private Difficulty difficulty; + private LevelType levelType; + private boolean reducedDebugInfo; + + @Override + public void writeSelf(NetByteBuf netByteBuf) { + netByteBuf.writeInt(entityId); + netByteBuf.writeUnsignedByte(gameMode.getId()); + netByteBuf.writeInt(dimension); + netByteBuf.writeUnsignedByte(difficulty.getId()); + netByteBuf.writeUnsignedByte(0); // Max Players, unused + netByteBuf.writeString(levelType.getType()); + netByteBuf.writeBoolean(reducedDebugInfo); + } +} diff --git a/server/src/main/java/mc/server/PacketHandler.java b/server/src/main/java/mc/server/PacketHandler.java index b016bd0..f3c8a67 100644 --- a/server/src/main/java/mc/server/PacketHandler.java +++ b/server/src/main/java/mc/server/PacketHandler.java @@ -2,13 +2,13 @@ package mc.server; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import mc.protocol.ChannelContext; -import mc.protocol.ProtocolConstant; +import mc.protocol.*; import mc.protocol.model.ServerInfo; import mc.protocol.packets.PingPacket; import mc.protocol.packets.client.HandshakePacket; import mc.protocol.packets.client.LoginStartPacket; import mc.protocol.packets.client.StatusServerRequestPacket; +import mc.protocol.packets.server.JoinGamePacket; import mc.protocol.packets.server.LoginSuccessPacket; import mc.protocol.packets.server.StatusServerResponse; import mc.protocol.serializer.TextSerializer; @@ -20,6 +20,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Base64; import java.util.Collections; +import java.util.Random; import java.util.UUID; @Slf4j @@ -27,6 +28,7 @@ import java.util.UUID; public class PacketHandler { private final Config config; + private final Random random = new Random(System.currentTimeMillis()); public void onHandshake(ChannelContext