Genesis
This commit is contained in:
264
protocol.md
Normal file
264
protocol.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user