Files
flayerproxy/protocol.md
2026-05-20 18:20:59 +02:00

265 lines
18 KiB
Markdown

# 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-<timestamp>.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.