38 lines
2.2 KiB
Markdown
38 lines
2.2 KiB
Markdown
# Architecture and Design
|
|
|
|
This project follows a strict Object-Oriented approach to manage the complexity of the OpenTTD network protocol.
|
|
|
|
## Component Overview
|
|
|
|
### 1. `OpenTTDProtocol` (Low-Level)
|
|
Inherits from `openttd_protocol.wire.tcp.TCPProtocol`.
|
|
- **Responsibility:** Binary serialization/deserialization and stream encryption.
|
|
- **Encryption Layer:** It overrides `send_packet` and `receive_packet` to wrap/unwrap AEAD (XChaCha20-Poly1305) payloads.
|
|
- **Manual Dispatch:** Uses a manual dispatch mechanism to ensure that even encrypted packets are correctly mapped to their high-level handlers.
|
|
|
|
### 2. `OpenTTDClient` (High-Level)
|
|
The primary API for developers.
|
|
- **Responsibility:** Handshake orchestration, state management, and keep-alive.
|
|
- **Event-Driven:** Uses `asyncio.Event` (like `self.joined`) to signal state changes to the calling code.
|
|
- **Callback System:** Provides hooks like `on_chat` to allow users to react to game events without modifying the core library.
|
|
|
|
## Handshake Flow
|
|
|
|
1. **Connection:** TCP connection established to Port 3979.
|
|
2. **Information:** `ClientGameInfo` sent to verify server version.
|
|
3. **Join:** `ClientJoin` sent with the specific JGRPP revision string.
|
|
4. **Authentication:** Server sends `ServerAuthenticationRequest` (Type 1: PAKE).
|
|
5. **PAKE Exchange:**
|
|
- Shared Secret derived via X25519.
|
|
- Session Keys derived via Blake2b hashing of (SharedSecret + ServerPub + OurPub + Password).
|
|
- Encrypted challenge sent back via `ClientAuthenticationResponse`.
|
|
6. **Encryption:** Server sends `ServerEnableEncryption`. The Protocol layer activates the AEAD stream.
|
|
7. **Identification:** `ClientIdentify` sent (now encrypted).
|
|
8. **Map Synchronization:** `ServerWelcome` received -> `ClientGetMap` sent -> Map segments received -> `ClientMapOk` sent.
|
|
9. **Active State:** `client.joined` is set. The client responds to `ServerFrame` with `ClientAck` to prevent timeouts.
|
|
|
|
## Error Handling
|
|
- **Shutdown Event:** Every fatal error or manual quit triggers a `shutdown_event`.
|
|
- **Graceful Exit:** The `quit()` method sends a `ClientQuit` packet before closing the transport.
|
|
- **Fallback:** Unknown packets are caught and mapped to `receive_ServerUnused` to prevent the simulation loop from crashing.
|