The station queries and the cargo events name a cargo only by a bare
numeric id -- get_station()'s and get_station_cargo()'s cargo_id, the
cargo_waiting events, the per-cargo load on vehicle events. Those ids
index the cargo table the loaded NewGRFs build for the running game, so
the same id is coal in one save and grain in another and callers had no
way to resolve them. The AdminBridge GameScript has answered a list_cargo
command all along; no method on OpenTTDAdminClient sent it. This adds the
missing half, so no GameScript change is needed for it to work.
It goes through _gs_query() like get_station(), inheriting the request_id
correlation and the Gamescript auto-subscribe, with one difference worth
knowing: the GS handler defines no error reply for this command, so unlike
the other queries it can time out but can never raise ValueError.
The reply lists cargo in GSCargoList order rather than by id -- against
the dev server the ids come back 10 down to 0 -- so the docstring and
PROTOCOL.md both warn to index the list by cargo_id and not by position.
Also teaches the main_admin.py demo to resolve the labels before printing
a station's cargo, which is what the bare ids in its output were asking
for all along.
Co-Authored-By: Claude <[email protected]>
Resolve 51 findings from the I/RUF/BLE/TRY002/S110/PLR0402 rule set:
- Sort imports and __all__ (I001, RUF022, PLR0402). The sys.path.insert
calls in check_public_calls.py and tests/test_e2e.py still precede the
openttd imports that depend on them.
- Replace unused unpacked values with _ (RUF059) and annotate the two
timetable lookup tables as ClassVar (RUF012).
- Narrow the best-effort excepts in OpenTTDClient.quit and
OpenTTDAdminClient.quit to (OSError, SocketClosed) and log at debug
rather than swallowing silently (BLE001, S110). The test doubles now
raise an OSError subclass so they still exercise that branch.
- Narrow the gamescript JSON fallback to json.JSONDecodeError. The broad
catch in receive_packet keeps a noqa: it guards untrusted wire data and
must degrade to a no-op packet instead of killing the connection.
- Use contextlib.suppress instead of try/except/pass in tests.
ruff check . is clean, 102 tests pass, coverage stays at 100%.
Co-Authored-By: Claude <[email protected]>
Editing (game port, OpenTTDClient): a core of JGRPP's scheduled dispatch
DoCommands — set_scheduled_dispatch (enable/disable), add/remove schedule,
add/remove/clear slots, and set duration/start date. Adds the command IDs
to protocol.py.
Viewing (admin, OpenTTDAdminClient.get_dispatch): the GameScript API has no
dispatch support, so a new server patch (docker/patches/0002-*) adds
read-only GSOrder.GetScheduledDispatch* / IsScheduledDispatchEnabled
getters, an AdminBridge GameScript get_dispatch handler exposes them, and
get_dispatch() returns the live schedules and slots (mirrors get_timetable).
Note: set_dispatch_start_date values are normalised by the engine relative
to current game time, so they read back offset from the requested value.
Includes unit + e2e tests, a demo in main.py, and protocol/timetable docs.
The AdminBridge GameScript and the patched OpenTTD-patches clone live
outside this repo; the 0002 patch file is the durable source for the latter.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Extends the AdminBridge GameScript JSON channel (the same relay used by
list_vehicles/get_timetable) with station support:
- list_stations(): enumerate stations, fire-and-forget like list_vehicles().
- get_station(): authoritative per-cargo snapshot of a station's live state,
with both the real-time waiting amount (GSStation.GetCargoWaiting) and the
planned cargodist link-graph flow (GetCargoPlanned), plus rating.
- get_station_cargo(): break one cargo type down by source station and by
next hop (the cargodist routing destination) for both waiting and planned
amounts, with optional from_station/via_station filters.
All three use stock GameScript API (no server patch, unlike timetables).
Refactors the shared GS request/reply correlation out of get_timetable and
get_station into a _gs_query() helper. Companion handlers must be added to
the server-side AdminBridge GameScript (not tracked in this repo).
Includes unit + e2e tests, a worked demo in main_admin.py, and protocol docs.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
The Admin Network has no native packet for listing individual vehicles,
so list_vehicles() sends a "list_vehicles" command over the existing
GameScript JSON channel and relies on a companion server-side script to
reply with vehicle data via ServerGamescript. Requires subscribing to
Gamescript updates (documented in docs/PROTOCOL.md) to receive the reply.
Co-Authored-By: Claude Sonnet 5 <[email protected]>