74 Commits
Author SHA1 Message Date
kovagoadi 24a244a07e Merge pull request 'Update debian:trixie-slim Docker digest to a99cfc5' (#32) from renovate/debian-trixie-slim into main
Continuous Integration / lint-and-security (push) Successful in 48s
Continuous Integration / tests-and-coverage (push) Successful in 27s
Reviewed-on: #32
2026-09-21 14:45:49 +02:00
kovagoadi e4dd22157b Merge branch 'main' into renovate/debian-trixie-slim
Continuous Integration / lint-and-security (pull_request) Successful in 51s
Continuous Integration / tests-and-coverage (pull_request) Successful in 1m19s
2026-09-21 14:37:11 +02:00
kovagoadi 7335d9b954 Merge pull request 'Update debian:13 Docker digest to 9cc0800' (#31) from renovate/debian-13 into main
Continuous Integration / lint-and-security (push) Successful in 1m4s
Continuous Integration / tests-and-coverage (push) Successful in 1m4s
Reviewed-on: #31
2026-09-21 14:36:45 +02:00
renovate-bot 355bef9d25 Update debian:trixie-slim Docker digest to a99cfc5
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
2026-09-20 02:22:56 +00:00
renovate-bot b2fa14b7ff Update debian:13 Docker digest to 9cc0800
Continuous Integration / lint-and-security (pull_request) Successful in 1m13s
Continuous Integration / tests-and-coverage (pull_request) Successful in 26s
2026-09-20 02:22:49 +00:00
kovagoadi f357653bbb Merge pull request 'Put the AdminBridge GameScript under version control' (#30) from claude/silly-lederberg-231f6c into main
Continuous Integration / lint-and-security (push) Successful in 20s
Continuous Integration / tests-and-coverage (push) Successful in 26s
Reviewed-on: #30
2026-08-31 19:19:33 +02:00
kovagoadiandClaude f9eeae39ed Merge branch 'main' into claude/silly-lederberg-231f6c
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
Conflicted only on the README feature list, where main's list_cargo()
bullet and this branch's bridge bullet were added at the same spot. Kept
both: list_cargo() with the other cargo queries, and the bridge one last,
since it is about what all of them run against.

list_cargo() landing also makes tests/test_gamescript.py's command check
meaningful in the other direction -- the bridge has answered list_cargo
all along with nothing sending it, which is exactly the asymmetry that
check tolerates on purpose.

Co-Authored-By: Claude <[email protected]>
2026-08-31 19:12:41 +02:00
kovagoadiandClaude aa9eda4b6d Fix import ordering in test_gamescript.py
ruff's isort rules want the openttd import grouped with the other
third-party imports, as the rest of the test suite has it.

Co-Authored-By: Claude <[email protected]>
2026-08-31 19:11:29 +02:00
kovagoadiandClaude f7ca395a4f Put the AdminBridge GameScript under version control
Continuous Integration / lint-and-security (pull_request) Failing after 19s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
The last commit noted in passing that the server-side half of the admin
GameScript channel "is not in this repo -- docker/config is gitignored --
so it has to be updated separately for any of this to work." That was true
of all nine features the README documents: list_vehicles, list_stations,
list_cargo, get_timetable, get_station, get_station_cargo, get_dispatch and
the event stream all answer from 705 lines of Squirrel that no clone could
reproduce, no reviewer could see, and CI never touched.

The bridge now lives in gamescript/AdminBridge/ with its own README, the
same arrangement docker/patches/ uses for the local JGRPP patches, and
docker-compose.yml bind-mounts it read-only over the container's
game/AdminBridge. docker/config stays ignored -- it also holds savegames,
downloaded content and generated config -- so the copy under it is now
shadowed and can be deleted. main.nut is byte-identical to what was running,
apart from the version work below.

Adds a version handshake, because the channel gives no way to tell a stale
bridge from a hung one: a bridge that does not recognise a command drops it
silently, so a client ahead of the server sees nothing but timeouts. The
bridge now answers get_version with its protocol version plus its command
and event catalogues, and get_bridge_version() raises when that is below
GS_BRIDGE_VERSION. It is opt-in rather than checked on connect: GameScripts
do not tick while the game is paused, so an automatic check would refuse to
connect to a paused server. A bridge older than 4 predates get_version
itself and can only fail by timing out, so the E2E test catches that and
reports it by name instead.

tests/test_gamescript.py gives CI a foothold on the GameScript without a
Squirrel toolchain: it parses the .nut files and pins the protocol version
across info.nut, main.nut and protocol.py, the event catalogue against
GameEventType, and the command table against the commands client.py sends.
The version has to be declared three times because a GameScript cannot read
its own info.nut at runtime -- GSController.GetVersion() returns the OpenTTD
version, not the script's.

info.nut also gains MinVersionToLoad() { return 1; }. The engine defaults it
to GetVersion(), so without it this bump would orphan every savegame pinned
to version 3: the scanner finds no compatible script and falls back with a
warning. The bridge keeps no savegame state, so any version can take over.

HandleCommand now dispatches through the same table get_version reports,
rather than an if/else chain, so the catalogue a client feature-detects
against cannot drift from what is implemented.

Co-Authored-By: Claude <[email protected]>
2026-08-31 19:06:33 +02:00
kovagoadi 0641d25858 Merge pull request 'Add list_cargo() to the admin client' (#29) from claude/infallible-visvesvaraya-8d8c8a into main
Continuous Integration / lint-and-security (push) Successful in 21s
Continuous Integration / tests-and-coverage (push) Successful in 25s
Reviewed-on: #29
2026-08-31 18:35:57 +02:00
kovagoadiandClaude ba26b59c40 Add list_cargo() to the admin client
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
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]>
2026-08-31 18:33:05 +02:00
kovagoadi 90a07392cf Merge pull request 'Add game event support to the admin client' (#28) from claude/vehicle-cargo-stop-events-79422a into main
Continuous Integration / lint-and-security (push) Successful in 21s
Continuous Integration / tests-and-coverage (push) Successful in 25s
Reviewed-on: #28
2026-08-31 18:24:44 +02:00
kovagoadiandClaude d87c779d94 Add game event support to the admin client
Continuous Integration / lint-and-security (pull_request) Successful in 41s
Continuous Integration / tests-and-coverage (pull_request) Successful in 28s
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]>
2026-08-31 18:14:40 +02:00
kovagoadi 28f247799e Merge pull request 'Update debian:trixie-slim Docker digest to d7e1218' (#26) from renovate/debian-trixie-slim into main
Continuous Integration / lint-and-security (push) Successful in 19s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #26
2026-08-26 21:08:13 +02:00
kovagoadi 6734c13963 Merge pull request 'Update debian:13 Docker digest to f324c7f' (#25) from renovate/debian-13 into main
Continuous Integration / lint-and-security (push) Successful in 19s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #25
2026-08-26 21:07:27 +02:00
kovagoadi 54f8a06862 Merge branch 'main' into renovate/debian-trixie-slim
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 23s
2026-08-26 21:06:26 +02:00
kovagoadi 3641bf383e Merge branch 'main' into renovate/debian-13
Continuous Integration / lint-and-security (pull_request) Successful in 19s
Continuous Integration / tests-and-coverage (pull_request) Successful in 23s
2026-08-26 21:06:04 +02:00
kovagoadi db7fb8e09a Merge pull request 'Fix ruff lint findings across client, protocol, and tests' (#27) from claude/ruff-import-sorting-bb5651 into main
Continuous Integration / lint-and-security (push) Successful in 22s
Continuous Integration / tests-and-coverage (push) Successful in 26s
Reviewed-on: #27
2026-08-26 21:05:46 +02:00
kovagoadiandClaude 25953bea06 Fix ruff lint findings across client, protocol, and tests
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
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]>
2026-08-26 20:57:56 +02:00
renovate-bot c5876b270a Update debian:trixie-slim Docker digest to d7e1218
Continuous Integration / lint-and-security (pull_request) Failing after 17s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
2026-08-26 02:21:55 +00:00
renovate-bot 1a2ea538e8 Update debian:13 Docker digest to f324c7f
Continuous Integration / lint-and-security (pull_request) Failing after 4m2s
Continuous Integration / tests-and-coverage (pull_request) Successful in 37s
2026-08-26 02:21:51 +00:00
kovagoadi 8e352ba248 Merge pull request 'Update debian:13 Docker digest to 34cd9e9' (#23) from renovate/debian-13 into main
Continuous Integration / lint-and-security (push) Failing after 33s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #23
2026-08-06 17:43:23 +02:00
kovagoadi 7fdd5f2fca Merge branch 'main' into renovate/debian-13
Continuous Integration / lint-and-security (pull_request) Successful in 23s
Continuous Integration / tests-and-coverage (pull_request) Successful in 27s
2026-08-06 17:38:42 +02:00
kovagoadi a9f5b2d5d9 Merge pull request 'Update debian:trixie-slim Docker digest to 3a39a05' (#24) from renovate/debian-trixie-slim into main
Continuous Integration / lint-and-security (push) Successful in 49s
Continuous Integration / tests-and-coverage (push) Successful in 30s
Reviewed-on: #24
2026-08-06 17:38:34 +02:00
renovate-bot e925659e28 Update debian:trixie-slim Docker digest to 3a39a05
Continuous Integration / lint-and-security (pull_request) Successful in 21s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
2026-08-06 02:22:05 +00:00
renovate-bot 846d085e1a Update debian:13 Docker digest to 34cd9e9
Continuous Integration / lint-and-security (pull_request) Successful in 1m0s
Continuous Integration / tests-and-coverage (pull_request) Successful in 28s
2026-08-06 02:22:00 +00:00
kovagoadi f0ef4148b0 Merge pull request 'Add scheduled dispatch support (edit + authoritative view)' (#22) from claude/station-realtime-planned-data-0fc51a into main
Continuous Integration / lint-and-security (push) Successful in 21s
Continuous Integration / tests-and-coverage (push) Successful in 25s
Reviewed-on: #22
2026-07-24 23:00:14 +02:00
kovagoadi 67e886f8d2 Merge branch 'main' into claude/station-realtime-planned-data-0fc51a
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
2026-07-24 22:58:39 +02:00
kovagoadiandClaude Opus 4.8 2eea541158 Add scheduled dispatch support (edit + authoritative view)
Continuous Integration / lint-and-security (pull_request) Successful in 22s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
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]>
2026-07-24 22:56:37 +02:00
kovagoadi af1a865fd6 Merge pull request 'Add station listing and cargo queries to admin client' (#21) from claude/station-realtime-planned-data-0fc51a into main
Continuous Integration / lint-and-security (push) Successful in 20s
Continuous Integration / tests-and-coverage (push) Successful in 23s
Reviewed-on: #21
2026-07-23 21:52:35 +02:00
kovagoadiandClaude Opus 4.8 81a4d9333d Add station listing and cargo queries to admin client
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
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]>
2026-07-23 21:48:20 +02:00
kovagoadi c39f970ef9 Merge pull request 'Added real timetable support' (#20) from add-real-timetable-support into main
Continuous Integration / lint-and-security (push) Successful in 20s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #20
2026-07-23 21:02:37 +02:00
kovagoadi 36fc118da3 Merge branch 'main' into add-real-timetable-support
Continuous Integration / lint-and-security (pull_request) Successful in 26s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
2026-07-23 21:00:50 +02:00
kovagoadi 3b54a722d6 Added real timetable support
Continuous Integration / lint-and-security (pull_request) Successful in 33s
Continuous Integration / tests-and-coverage (pull_request) Successful in 26s
2026-07-23 20:59:28 +02:00
kovagoadi 38cc5ae40c Merge pull request 'Update actions/setup-python action to v7' (#19) from renovate/actions-setup-python-7.x into main
Continuous Integration / lint-and-security (push) Successful in 20s
Continuous Integration / tests-and-coverage (push) Successful in 23s
Reviewed-on: #19
2026-07-21 20:09:28 +02:00
kovagoadi dfb88523f1 Merge branch 'main' into renovate/actions-setup-python-7.x
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
2026-07-21 20:07:54 +02:00
kovagoadi 5db0dab9bf Merge pull request 'Update actions/checkout digest to 3d3c42e' (#18) from renovate/actions-checkout-digest into main
Continuous Integration / lint-and-security (push) Successful in 22s
Continuous Integration / tests-and-coverage (push) Successful in 26s
Reviewed-on: #18
2026-07-21 20:07:47 +02:00
renovate-bot 71bef5a8a2 Update actions/setup-python action to v7
Continuous Integration / lint-and-security (pull_request) Successful in 1m55s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
2026-07-21 02:22:10 +00:00
renovate-bot df9c7b3f06 Update actions/checkout digest to 3d3c42e
Continuous Integration / lint-and-security (pull_request) Successful in 55s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
2026-07-21 02:22:05 +00:00
kovagoadi 954663e80c Merge pull request 'Add vehicle timetable get/set support' (#17) from claude/listing-vehicles-support-d07bf0 into main
Continuous Integration / lint-and-security (push) Successful in 21s
Continuous Integration / tests-and-coverage (push) Successful in 25s
Reviewed-on: #17
2026-07-16 23:26:14 +02:00
kovagoadi 6a28e4acff Merge branch 'main' into claude/listing-vehicles-support-d07bf0
Continuous Integration / lint-and-security (pull_request) Successful in 21s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
2026-07-16 23:25:21 +02:00
kovagoadiandClaude Sonnet 5 b33869334a Add vehicle timetable get/set support
Continuous Integration / lint-and-security (pull_request) Successful in 22s
Continuous Integration / tests-and-coverage (pull_request) Successful in 24s
Timetables have no GameScript API surface, so this implements real
DoCommands over the game port (ClientCommand/ServerCommand) instead of
the Admin GameScript relay used for list_vehicles(): change_timetable(),
autofill_timetable(), set_timetable_start(), and set_vehicle_on_time()
send commands, while get_vehicle_timetable() reconstructs state purely
by observing ServerCommand broadcasts, since no query command exists.

Includes the custom varuint wire codec these commands require, a full
usage guide (docs/TIMETABLES.md), and a worked demo in main.py.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-16 23:21:21 +02:00
kovagoadi fa1741f95b Merge pull request 'Add vehicle listing support to admin client' (#16) from claude/listing-vehicles-support-d07bf0 into main
Continuous Integration / lint-and-security (push) Successful in 22s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #16
2026-07-16 20:46:58 +02:00
kovagoadiandClaude Sonnet 5 0a8271d57c Add vehicle listing support to admin client
Continuous Integration / lint-and-security (pull_request) Successful in 31s
Continuous Integration / tests-and-coverage (pull_request) Successful in 25s
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]>
2026-07-16 20:44:44 +02:00
kovagoadi 309f1da762 Merge pull request 'Update debian Docker tag to trixie-20260713' (#15) from renovate/debian-13.x into main
Continuous Integration / lint-and-security (push) Successful in 20s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #15
2026-07-15 09:14:53 +02:00
kovagoadi 2526b8aec4 Merge branch 'main' into renovate/debian-13.x
Continuous Integration / lint-and-security (pull_request) Successful in 21s
Continuous Integration / tests-and-coverage (pull_request) Successful in 23s
2026-07-15 09:13:54 +02:00
kovagoadi 38e0604cf3 Merge pull request 'Update debian:bookworm-slim Docker digest to 7b140f3' (#14) from renovate/debian-bookworm-slim into main
Continuous Integration / lint-and-security (push) Successful in 22s
Continuous Integration / tests-and-coverage (push) Successful in 24s
Reviewed-on: #14
2026-07-15 09:13:09 +02:00
renovate-bot d87f26a8ef Update debian Docker tag to trixie-20260713
Continuous Integration / lint-and-security (pull_request) Successful in 20s
Continuous Integration / tests-and-coverage (pull_request) Successful in 23s
2026-07-15 02:22:08 +00:00
renovate-bot d0c4d9218d Update debian:bookworm-slim Docker digest to 7b140f3
Continuous Integration / lint-and-security (pull_request) Successful in 48s
Continuous Integration / tests-and-coverage (pull_request) Successful in 26s
2026-07-15 02:22:04 +00:00
kovagoadi ab8ab7390e Merge pull request 'Update debian Docker tag to v13' (#13) from renovate/debian-13.x into main
Continuous Integration / lint-and-security (push) Successful in 30s
Continuous Integration / tests-and-coverage (push) Successful in 23s
Reviewed-on: #13
2026-07-03 14:48:46 +02:00