# 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. ### 3. `OpenTTDAdminClient` (Admin Network) Talks to the Admin port (TCP 3977) and, through the AdminBridge GameScript's JSON channel, to the running game itself. - **Correlated Queries:** `get_timetable()`, `get_station()`, `get_dispatch()` and friends all funnel through `_gs_query()`, which tags each request with a monotonic `request_id`, parks a future, and lets `receive_ServerGamescript` resolve it when the matching reply arrives. - **Push Events:** `subscribe_events()` opens the one stream that flows the other way. Event batches carry no `request_id`, so `receive_ServerGamescript` routes them to the event consumers instead: each event goes to the longest-waiting matching `wait_for_event()` caller, or into a bounded buffer if nobody is waiting, and to the `on_event` observer either way. See [EVENTS.md](EVENTS.md). ## 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.