# Minecraft Server: Login Flow & World Synchronization This document outlines the detailed protocol sequences, state transitions, and network synchronization mechanisms used in the Minecraft server, based on the codebase in `serversSrc`. --- ## 1. Connection Handshake & Protocol Transition When a client initiates a connection to a Minecraft server, it starts in the **Handshake** protocol. This is handled by [ServerHandshakePacketListenerImpl](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java). ```mermaid sequenceDiagram autonumber participant Client participant Server (Handshake) participant Server (Login) participant Mojang Session Service participant Server (Config) Client->>Server (Handshake): ClientIntentionPacket (Intention=LOGIN, protocolVersion) Note over Server (Handshake): Validates protocol version Server (Handshake)->>Server (Login): Instantiate ServerLoginPacketListenerImpl Client->>Server (Login): ServerboundHelloPacket (name) alt Offline Mode Server (Login)->>Server (Login): startClientVerification (Offline UUID) else Online Mode Server (Login)-->>Client: ClientboundHelloPacket (ServerID, public key, challenge) Client->>Server (Login): ServerboundKeyPacket (encrypted shared secret, encrypted challenge) Note over Server (Login): Decrypts secret & sets up AES encryption Server (Login)->>Mojang Session Service: hasJoinedServer(username, digest, IP) Mojang Session Service-->>Server (Login): GameProfile (UUID, textures) end Note over Server (Login): verifyLoginAndFinishConnectionSetup Server (Login)-->>Client: ClientboundLoginCompressionPacket (optional) Server (Login)-->>Client: ClientboundLoginFinishedPacket Client->>Server (Login): ServerboundLoginAcknowledgedPacket Server (Login)->>Server (Config): Switch protocol, instantiate ServerConfigurationPacketListenerImpl ``` ### Protocol Steps: 1. **Client Intention**: The client sends a `ClientIntentionPacket` indicating its target state: - `STATUS`: The client is pinging the server for info (MOTD, online players). - `LOGIN`/`TRANSFER`: The client wants to connect to the game server. 2. **Version Verification**: The server verifies that the client's protocol version matches the server's current version: - If mismatched, the server sends a `ClientboundLoginDisconnectPacket` and closes the socket. - If matching, the server transitions the connection to the `Login` protocol state and spawns a [ServerLoginPacketListenerImpl](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/network/ServerLoginPacketListenerImpl.java). --- ## 2. Login Protocol Phase The login protocol handles authentication, encryption setup, and duplicate connection handling. ### Step-by-Step Flow: 1. **Hello**: The client sends its username inside a `ServerboundHelloPacket`. 2. **Authentication Determination**: - **Offline Mode**: The server bypasses encryption/auth, creates an offline UUID profile, and starts verification. - **Online Mode**: The server transitions to the `KEY` state and sends a `ClientboundHelloPacket` containing a random challenge token, the server's public key, and server ID. 3. **Encryption Setup**: - The client generates a shared secret symmetric key (AES), encrypts it and the challenge token using the server's RSA public key, and sends it back in a `ServerboundKeyPacket`. - The server decrypts the shared secret and challenge token using its private key. It verifies the challenge matches. - Symmetric AES encryption is initialized on the network socket (`connection.setEncryptionKey(...)`). 4. **Session Verification**: - The server computes a SHA-1 hash (server ID + shared secret + server public key) and sends a request to Mojang's session servers to verify if the client has successfully authenticated their session (`hasJoinedServer`). - If verified, the server receives the client's official `GameProfile` (UUID, username, skin textures, etc.). 5. **Verifying and Compression**: - The server verifies if the player is allowed to connect (checks `UserBanList`, `IpBanList`, `UserWhiteList`, and server full limitations via `PlayerList.canPlayerLogin`). - If a compression threshold is configured in `server.properties`, the server sends a `ClientboundLoginCompressionPacket` and turns on network compression. - **Duplicate Connection Check**: The server disconnects any existing players with the same UUID. 6. **Finished Protocol Transition**: - The server sends a `ClientboundLoginFinishedPacket` to notify the client that the login phase is complete. - The client acknowledges this by responding with `ServerboundLoginAcknowledgedPacket`. - The server switches the connection to the **Configuration** protocol and creates a [ServerConfigurationPacketListenerImpl](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java). --- ## 3. Configuration Phase The server configuration phase is a task-based queue that sets up registry entries, client/server resource settings, and initial spawn calculations before the player actually joins the world. ```mermaid sequenceDiagram autonumber participant Client participant Server (Config) Note over Server (Config): startConfiguration() Server (Config)-->>Client: Brand / Server Links / Update Features Packets Server (Config)-->>Client: Registry/Pack select request (SynchronizeRegistriesTask) Client->>Server (Config): ServerboundSelectKnownPacks Note over Server (Config): PrepareSpawnTask (Loads player data & chunks) Note over Server (Config): JoinWorldTask (Sends finish config packet) Server (Config)-->>Client: ClientboundFinishConfigurationPacket Client->>Server (Config): ServerboundFinishConfigurationPacket Note over Server (Config): Transition connection to Play state ``` ### Configuration Task Queue: - **Server Identity**: The server sends initial information like brand name (`ClientboundCustomPayloadPacket` with `BrandPayload`) and links (`ClientboundServerLinksPacket`). - **SynchronizeRegistriesTask**: Sends the server's known resource packs and waits for the client to acknowledge with `ServerboundSelectKnownPacks`. The server then replies with `ClientboundRegistryDataPacket` and `ClientboundUpdateTagsPacket`. - **Optional Tasks**: - `ServerCodeOfConductConfigurationTask`: Prompts client to accept terms. - `ServerResourcePackConfigurationTask`: Sends resource pack download prompts. - **PrepareSpawnTask**: 1. Loads player data (position, rotation, dimension). 2. Asynchronously requests spawn chunk loading (radius of 3 chunks around player spawn position). 3. Holds configuration tick execution until the client's immediate spawn area is fully loaded and ready. - **JoinWorldTask**: Sends `ClientboundFinishConfigurationPacket` to trigger play state transition. - **Transition**: - The client responds with `ServerboundFinishConfigurationPacket`. - The server updates the network handler to the **Play** protocol template (`GameProtocols.CLIENTBOUND_TEMPLATE.bind(...)`). - The server spawns the player into the level and hands control to [ServerGamePacketListenerImpl](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/network/ServerGamePacketListenerImpl.java). --- ## 4. Play State Transition (Initial World Sync) When the connection transitions to the **Play** state, [PlayerList.placeNewPlayer()](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/players/PlayerList.java#L141-L194) sends a dense stream of packets to synchronize the player's HUD, environment, inventory, and initial chunks. ``` [ Client ] [ Server (Play) ] | | | <----------- ClientboundLoginPacket -------------| (EID, difficulty, dimensions...) | <------- ClientboundChangeDifficultyPacket ------| (Current difficulty state) | <------ ClientboundPlayerAbilitiesPacket -------| (Flying/creative capabilities) | <-------- ClientboundSetHeldSlotPacket ----------| (Active hotbar slot index) | <------- ClientboundUpdateRecipesPacket ---------| (Synchronize recipes) | <--------- Send Commands Tree Packet ------------| (Command syntax helper) | <------ ClientboundPlayerInfoUpdatePacket -------| (Initialize online tab list) | <--------- Teleport Packet to Spawn -------------| (Pos/Rot snap location) | | | (Send World Info) | | <----- ClientboundInitializeBorderPacket --------| (World border settings) | <------------- Synchronize Clock Packet ---------| (World time / day-night tick) | <---- ClientboundSetDefaultSpawnPositionPacket --| (World spawn coordinate) | <--------- ClientboundGameEventPacket -----------| (Weather updates: Rain/Thunder) | <-------- LEVEL_CHUNKS_LOAD_START Event ---------| (Trigger client chunk loading) | | | (Active Entities & Chunks) | | <------- ClientboundUpdateMobEffectPacket -------| (Apply ongoing status effects) | <--------- Initialize Inventory Packet ----------| (Fill inventory UI slots) ``` 1. **ClientboundLoginPacket**: Sets up core game parameters (Entity ID, hardcore mode, view distance, simulation distance). 2. **ClientboundChangeDifficultyPacket & ClientboundPlayerAbilitiesPacket**: Syncs world difficulty and character flight/speed settings. 3. **ClientboundSetHeldSlotPacket**: Syncs the player's currently selected hotbar slot. 4. **ClientboundUpdateRecipesPacket**: Syncs stonecutter and generic crafting recipes. 5. **Commands & Permissions**: Sends operator status and command syntax mappings. 6. **Scoreboard & Teams**: Sends objective lists and color styling data (`updateEntireScoreboard`). 7. **Player List Info**: Sends `ClientboundPlayerInfoUpdatePacket` to add the joining player and all current players to the tab list. 8. **Position Teleport**: Teleports the player's local camera to the spawn position. 9. **Environment/Weather**: Syncs the world border, time of day, default spawn points, and weather conditions (e.g., `START_RAINING`, `RAIN_LEVEL_CHANGE`). 10. **Start Level Sync**: Sends a game event of type `LEVEL_CHUNKS_LOAD_START` to indicate to the client that it should prepare to receive chunk data. --- ## 5. Live World Synchronization Mechanisms Once a player is in the world, the server continuously updates the player's client via three loops: **Chunk Sync**, **Entity Sync**, and **World State Sync**. ```mermaid sequenceDiagram autonumber participant Client participant Server (Play) Note over Server (Play): PlayerList.placeNewPlayer() Server (Play)-->>Client: ClientboundLoginPacket (Entity ID, Dimension keys, View distance...) Server (Play)-->>Client: ChangeDifficulty / PlayerAbilities / SetHeldSlot / UpdateRecipes Packets Server (Play)-->>Client: Teleport (initial position) Server (Play)-->>Client: InitializeBorder / Sync Time / DefaultSpawnPosition Packets Server (Play)-->>Client: LEVEL_CHUNKS_LOAD_START Game Event rect rgb(200, 220, 240) Note over Server (Play), Client: Chunk Synchronization Loop Server (Play)-->>Client: ClientboundChunkBatchStartPacket Server (Play)-->>Client: ClientboundLevelChunkWithLightPacket (multiple chunks) Server (Play)-->>Client: ClientboundChunkBatchFinishedPacket end rect rgb(220, 240, 200) Note over Server (Play), Client: Entity Tracking Loop Server (Play)-->>Client: ClientboundBundlePacket (Spawn Entity, Metadata, Attributes, Equipment) Server (Play)-->>Client: ClientboundMoveEntityPacket / EntityPositionSyncPacket / RotateHeadPacket Server (Play)-->>Client: ClientboundRemoveEntitiesPacket (when entity out of range) end rect rgb(240, 200, 220) Note over Server (Play), Client: Dynamic World State Loop Server (Play)-->>Client: ClientboundBlockUpdatePacket (single block) Server (Play)-->>Client: ClientboundSectionBlocksUpdatePacket (multiple blocks in section) Server (Play)-->>Client: ClientboundLightUpdatePacket (lighting recalculations) end ``` ### A. Chunk Synchronization Minecraft manages which chunks are loaded on the client through the player's view distance and [ChunkTrackingView](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/level/ChunkMap.java#L1031-L1065). - **Movement Tracking**: As a player walks, the difference between their previous `ChunkTrackingView` and current `ChunkTrackingView` is computed: - **New Chunks**: Scheduled for sending via `markChunkPendingToSend(player, chunk)`. - **Old Chunks**: Cleared from the client via `ClientboundForgetLevelChunkPacket`. - **Chunk Batching**: To prevent network congestion, the server uses [PlayerChunkSender](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/network/PlayerChunkSender.java) to batch chunks: 1. Sends a `ClientboundChunkBatchStartPacket`. 2. Sends individual chunk data using `ClientboundLevelChunkWithLightPacket` (containing blocks, state mappings, tile entities, and light values). 3. Sends `ClientboundChunkBatchFinishedPacket` confirming the batch size. 4. Waits for the client to acknowledge before sending the next batch (the batch rate dynamically throttles based on the client's processing feedback). --- ### B. Entity Tracking & Synchronization The server tracks close entities (players, items, projectiles, mobs) on a per-player basis using [ChunkMap.TrackedEntity](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/level/ChunkMap.java#L1287-L1405). #### 1. Spawn Sync (Adding a Pairing) When an entity enters a player's tracking range: 1. The server calls `addPairing(player)`, collecting all initialization packets. 2. It packs them inside a `ClientboundBundlePacket` to guarantee atomic client rendering: - `getAddEntityPacket(...)`: Spawns the visual representation of the entity. - `ClientboundSetEntityDataPacket`: Syncs metadata values (e.g., if a creeper is ignited, if a wolf is sitting). - `ClientboundUpdateAttributesPacket`: Syncs movement speed, health limits, etc. - `ClientboundSetEquipmentPacket`: Syncs armor, shield, and hand items. - `ClientboundSetPassengersPacket`: Syncs riding links. #### 2. Position & State Sync (Incremental Updates) Every tick, the server runs `sendChanges()` inside [ServerEntity](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/level/ServerEntity.java#L89-L227): - **Relative Movement**: If the movement delta since the last packet is small, the server encodes it using a `VecDeltaCodec` (fitting into a `short` representation) and sends: - `ClientboundMoveEntityPacket.Pos` (position only) - `ClientboundMoveEntityPacket.Rot` (rotation only) - `ClientboundMoveEntityPacket.PosRot` (both position and rotation) - **Hard Synced Teleportation**: If the displacement exceeds the short delta limit, the riding/grounded state changes, or 400 ticks (`FORCED_TELEPORT_PERIOD`) have passed, the server sends a `ClientboundEntityPositionSyncPacket` to force-snap the position. - **Head Rotation**: Head yaw changes are tracked separately and sent via `ClientboundRotateHeadPacket`. - **Velocity**: Real-time motion forces (like knockback) are sent using `ClientboundSetEntityMotionPacket`. #### 3. Despawn Sync (Removing a Pairing) When an entity is destroyed or moves out of the player's tracking range, `removePairing(player)` is executed, sending a `ClientboundRemoveEntitiesPacket` to free memory on the client. --- ### C. Dynamic World State Updates Real-time edits to the environment (player building, chest placements, water flows) are pushed block-by-block using [ChunkHolder](file:///home/seb/flayerproxy/serversSrc/net/minecraft/server/level/ChunkHolder.java#L116-L232): - **Block Change Recording**: When a block updates, `blockChanged(pos)` records the position relative to its 16x16x16 section. - **Broadcasting Updates**: - **Single Block Change**: The server sends a `ClientboundBlockUpdatePacket` containing the coordinate and the new block state. - **Multiple Block Changes**: If multiple blocks update in the same section within a single tick, they are consolidated and sent as a `ClientboundSectionBlocksUpdatePacket` to save bandwidth. - **Tile Entities**: If the updated block holds a block entity (like a sign, container, or banner), the server fetches and broadcasts its NBT tag via `ClientboundBlockEntityDataPacket`. - **Light Recalculation**: If block updates affect ambient brightness, a `ClientboundLightUpdatePacket` is broadcasted. --- ## Packet sniffer proxy (development) MITM proxy: the Java client connects to a local `minecraft-protocol` server; the sniffer opens a second authenticated client to `config.server` and relays decrypted packets both ways while logging to JSONL. ```bash npm run sniffer ``` - Listens on `config.sniffer.port` (default **25567**); upstream target is `config.server`. - Connect the Java client to the sniffer (not 25566). One client at a time. - Logs: `logs/sniffer/session-.jsonl` with `"type":"packet"` entries (`dir`, `state`, `name`, payload or summary). - `sniffer.upstreamAuth`: `"microsoft"` (default) or `"offline"` for the upstream leg. - `sniffer.onlineMode`: `false` (default) lets the Java client join the sniffer without Mojang checking the sniffer itself; upstream still uses `upstreamAuth`. - Server list **ping** (`nextState: 1`) uses a raw TCP pass-through; **Join** (`nextState: 2`) runs the MITM path (login, `registry_data`, `map_chunk`, …). - `registry_data` / chunk packets are relayed with `writeRaw` where needed so NBT stays byte-identical. For the main FlayerProxy handoff path (25566), captured upstream config is still replayed with `writeRaw` so registry NBT stays byte-identical.