d87c779d94830c04edf09ae4d4154058fae114c6
Everything on the admin GameScript channel so far has been request/reply. This adds the other direction: subscribe_events() opens a push stream so a bot can react to the game instead of polling it, consumed either by awaiting wait_for_event() or via an on_event callback. Both see every event; an event goes to at most one waiter, and unclaimed ones sit in a bounded buffer. Sixteen kinds, from two sources. The engine raises no GameScript event for a vehicle reaching a stop or cargo arriving, so vehicle_arrive, vehicle_depart and cargo_waiting are synthesised by the bridge sampling state every `interval` ticks and diffing against the previous sample -- which means a stop shorter than the interval is never reported, and the first sample only establishes a baseline. The rest (crashes, industries, towns, companies, subsidies) are engine events forwarded verbatim. vehicle_lost, vehicle_waiting_in_depot and vehicle_unprofitable are deliberately absent: the engine raises those only for AI companies, so a GameScript can never observe them. The server-side half lives in the AdminBridge GameScript, which is not in this repo -- docker/config is gitignored -- so it has to be updated separately for any of this to work. Also repoints the scheduled-dispatch E2E test at a dedicated vehicle (DISPATCH_VEHICLE_ID). It had been silently skipping because vehicle 7 carries a hand-built annual dispatch schedule, which left eight dispatch methods unverified end to end while check_public_calls.py reported them green off static analysis of the call sites. Co-Authored-By: Claude <[email protected]>
Merge pull request 'Update debian:trixie-slim Docker digest to d7e1218' (#26) from renovate/debian-trixie-slim into main
OpenTTD Python Client
A high-performance, Object-Oriented Python client for OpenTTD servers, specifically optimized for JGR Patch Pack (JGRPP). This client handles the modern secure handshake, including X25519 PAKE authentication and AEAD stream encryption.
🚀 Features
- Secure Authentication: Full implementation of X25519 PAKE (Password-Authenticated Key Exchange).
- Stream Encryption: Automatic XChaCha20-Poly1305 authenticated encryption for all game traffic.
- Modular Design: Separates low-level binary protocol handling from high-level game logic.
- State Management: Handles the full join sequence including Map download and synchronization.
- Comprehensive Testing: Robustly tested with unit, logic, and E2E tests (including 100% coverage for unit/logic tests).
- Vehicle Listing: Query vehicle data via the Admin GameScript channel with
list_vehicles(). - Vehicle Timetables: Read and modify a vehicle's timetable (
change_timetable(),autofill_timetable(),set_timetable_start(),set_vehicle_on_time(),get_vehicle_timetable()) via real game-protocol commands. - Order Editing: Add and remove a vehicle's orders (
add_order()inserts a "go to station" stop,remove_order()deletes one) via real game-protocol commands. - Scheduled Dispatch (JGRPP): Edit a vehicle's dispatch schedules and departure slots over the game port (
add_dispatch_schedule(),add_dispatch_slot(),set_dispatch_duration(),set_scheduled_dispatch(), and more), and read them back authoritatively withOpenTTDAdminClient.get_dispatch()(via a patched GameScript API + the AdminBridge GS). - Authoritative Timetable Reads:
OpenTTDAdminClient.get_timetable()fetches the real, current timetable of any vehicle from the running game (via a patched GameScript API + the AdminBridge GS) — no company join needed, works for timetables set before connecting. - Station Listing: Enumerate stations via the Admin GameScript channel with
list_stations(). - Station Cargo Snapshots:
OpenTTDAdminClient.get_station()returns a station's live per-cargo state from the running game — both the real-time amount waiting and the planned flow through the cargodist link graph — over the AdminBridge GS (stock GameScript API, no server patch needed). - Cargo Flow Breakdown:
OpenTTDAdminClient.get_station_cargo()breaks one cargo type down by source station and next hop (routing destination) for both waiting (real-time) and planned amounts, with optionalfrom_station/via_stationfilters. - Game Events: react to the game instead of polling it —
subscribe_events()streams events over the AdminBridge GS as they happen: a vehicle reaching or leaving a stop (vehicle_arrive/vehicle_depart, with dwell time and cargo aboard), a station's waiting cargo changing (cargo_waiting), plus crashes, industries opening/closing, towns, companies and subsidies. Consume them withawait wait_for_event()or anon_eventcallback; filter by kind, company, vehicle, station or cargo.
🛠 Setup
Prerequisites
- Python 3.11+
- A running OpenTTD server (preferably JGRPP)
Installation
- Create and activate a virtual environment:
python3 -m venv venv source venv/bin/activate # Linux/macOS - Install dependencies:
pip install openttd-protocol pymonocypher
📖 Usage
Running the default client
The main.py script is configured to join the local server and the company "Én transport".
python3 main.py [Username] [CompanyID]
Example:
python3 main.py MyBot 0
Module Integration
You can use the openttd package in your own projects:
from openttd import OpenTTDClient
client = OpenTTDClient(host="127.0.0.1", username="BotName")
await client.connect(server_password="asd")
await client.join_company(company_id=0, company_password="asd123")
await client.joined.wait()
# Your logic here...
📂 Project Structure
main.py: Main entry point and usage example.lib/openttd/: Core package containing the protocol and client logic.docs/: Extensive documentation on architecture, protocol, and contributing.tests/: Comprehensive test suite (Logic, Protocol, E2E).
🧪 Testing
We maintain high test coverage. To run normal (non-E2E) tests:
pytest -m "not e2e"
For detailed instructions on E2E testing and coverage reports, see the Testing Guide.
📜 Documentation
Languages
Python
86.6%
Squirrel
12.7%
Dockerfile
0.7%