Add scheduled dispatch support (edit + authoritative view)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -336,6 +336,74 @@ async def main():
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Adding and removing orders
|
||||
|
||||
Beyond editing an order's timetable fields, you can change the order list itself. Both commands go
|
||||
over the game port and require being joined to the company that owns the vehicle (like the timetable
|
||||
methods above).
|
||||
|
||||
```python
|
||||
# Append a "go to station" order (station id 6) to the end of vehicle 7's order list.
|
||||
await client.add_order(7, 6)
|
||||
|
||||
# Insert one before position 0 instead of appending.
|
||||
await client.add_order(7, 6, before_position=0)
|
||||
|
||||
# Non-stop / stop-location can be customised (defaults suit every vehicle type).
|
||||
from openttd.protocol import OrderNonStopFlags
|
||||
await client.add_order(7, 6, non_stop=OrderNonStopFlags.NoStopAtIntermediate)
|
||||
|
||||
# Delete the order at a given position.
|
||||
await client.remove_order(7, 0)
|
||||
```
|
||||
|
||||
`add_order()` builds "go to station" orders. `stop_location` defaults to `PlatformFarEnd` because the
|
||||
other stop locations are train-only and rejected for road vehicles, ships and aircraft. There is no
|
||||
game-port query for the resulting order list; confirm changes with the admin `get_timetable()` order
|
||||
count (see [PROTOCOL.md](PROTOCOL.md#adding--removing-orders)).
|
||||
|
||||
## Scheduled dispatch (JGRPP)
|
||||
|
||||
Scheduled dispatch lets a vehicle depart on a fixed schedule of slots rather than purely by
|
||||
timetable. A vehicle's order list can hold several dispatch schedules, each with a duration, a start
|
||||
tick and a set of departure slots. The edit commands go over the game port and require being joined
|
||||
to the owning company; the authoritative read is on the admin client.
|
||||
|
||||
```python
|
||||
# Create a schedule (start tick 0, duration 3000 ticks) — it becomes the next schedule index.
|
||||
await client.add_dispatch_schedule(7, 0, 3000)
|
||||
|
||||
# Add departure slots at offsets 500 and 1500 within schedule 0's duration.
|
||||
await client.add_dispatch_slot(7, 0, 500)
|
||||
await client.add_dispatch_slot(7, 0, 1500)
|
||||
|
||||
# Add several evenly spaced slots at once: offset 0, then +250 three more times.
|
||||
await client.add_dispatch_slot(7, 0, 0, interval=250, extra_slots=3)
|
||||
|
||||
# Adjust the schedule, then turn scheduled dispatch on for the vehicle.
|
||||
await client.set_dispatch_duration(7, 0, 4000)
|
||||
await client.set_dispatch_start_date(7, 0, 1_000_000)
|
||||
await client.set_scheduled_dispatch(7, True)
|
||||
|
||||
# Remove a slot, clear a schedule's slots, or remove the whole schedule.
|
||||
await client.remove_dispatch_slot(7, 0, 1500)
|
||||
await client.clear_dispatch_schedule(7, 0)
|
||||
await client.remove_dispatch_schedule(7, 0)
|
||||
```
|
||||
|
||||
Read the live state back over the admin connection (requires the patched JGRPP build, see
|
||||
[docker/patches/README.md](../docker/patches/README.md)):
|
||||
|
||||
```python
|
||||
data = await admin.get_dispatch(7)
|
||||
# {"enabled": 1, "schedules": [{"index": 0, "duration": 4000, "start_tick": 1000000,
|
||||
# "delay": 0, "reuse_slots": 0, "slots": [{"offset": 500, "flags": 0}, ...]}]}
|
||||
```
|
||||
|
||||
The client implements a common core of the ~22 JGRPP dispatch commands; advanced operations
|
||||
(departure routes/tags, per-slot flags, adjust/swap/duplicate) are not wrapped yet.
|
||||
|
||||
## See also
|
||||
- [PROTOCOL.md — Vehicle Timetables](PROTOCOL.md#vehicle-timetables-game-port-docommands) for the underlying wire format.
|
||||
- [PROTOCOL.md — Vehicle Orders & Timetables](PROTOCOL.md#vehicle-orders--timetables-game-port-docommands) for the underlying wire format.
|
||||
- [PROTOCOL.md — Dispatch Query](PROTOCOL.md#dispatch-query) for the admin `get_dispatch()` read.
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) for how `OpenTTDClient` fits into the rest of the library.
|
||||
|
||||
Reference in New Issue
Block a user