265 lines
18 KiB
Markdown
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.
|