NPC Shuttle — Earth-Luna Corridor
Issue: #749 (depends on #748) Parent Epic: #747 (NPC Traffic)
Summary
A single NPC fast frigate shuttles continuously between Gateway Station (Earth MEO) and Lunar Gateway (Luna L5). Uses the existing brachistochrone rendezvous system with dock-on-arrival.
This is the first NPC ship in the game — a proof of concept that validates cross-body brachistochrone rendezvous works reliably end-to-end.
Design Principle: NPCs Are Just Ships with Automation Rules
There is no separate NPC controller or behavior engine. An NPC ship is a regular ship with:
is_npc: trueflag (for client labeling)- Automation rules configured by the admin (same system players use)
The admin sets up the NPC’s automation loop through the admin dashboard — exactly the same way a player would configure their own ship’s automation, just done on behalf of an NPC ship. This means:
- No NPC-specific state machine code
- No NPC-specific tick processing
- The existing automation engine handles everything
- Admin can modify NPC behavior at runtime by editing rules
NPC Ship Properties
| Property | Value |
|---|---|
| Name | NPC Shuttle 1 |
| Ship class | fast_frigate |
| Owner (player_id) | npc (reserved non-UUID player ID) |
| is_npc | true |
| System | Sol |
The NPC ship is a regular ship in the physics engine — same mass, fuel, thrust, drag, attitude dynamics as any player fast frigate.
Shuttle Automation Rules
The admin configures these rules on the NPC ship via the admin dashboard:
Rule 1 — Depart to Lunar Gateway when refueled and docked at Gateway Station:
{
"name": "Depart to Luna",
"trigger": {"conditions": [
{"field": "ship.fuel_pct", "op": ">=", "value": 100},
{"field": "ship.docked_station", "op": "==", "value": "<gateway_station_id>"}
]},
"actions": [
{"action": "undock"},
{"action": "rendezvous",
"target_id": "<lunar_gateway_id>",
"target_type": "station",
"strategy": "brachistochrone",
"dock_on_arrival": true}
],
"delay": 60
}
Rule 2 — Depart to Gateway Station when refueled and docked at Lunar Gateway:
{
"name": "Depart to Earth",
"trigger": {"conditions": [
{"field": "ship.fuel_pct", "op": ">=", "value": 100},
{"field": "ship.docked_station", "op": "==", "value": "<lunar_gateway_id>"}
]},
"actions": [
{"action": "undock"},
{"action": "rendezvous",
"target_id": "<gateway_station_id>",
"target_type": "station",
"strategy": "brachistochrone",
"dock_on_arrival": true}
],
"delay": 60
}
The delay field represents dwell time (seconds game time) after conditions are
met before executing actions. This gives the ship time at the station before
departing.
Automation System Extensions (Prerequisite — #748)
New Conditions
| Field | Type | Description |
|---|---|---|
ship.fuel_pct |
float (0-100) | Fuel as percentage of capacity |
ship.docked |
bool (0/1) | Whether ship is currently docked |
ship.docked_station |
string | Station ID the ship is docked at |
New Actions
| Action | Parameters | Description |
|---|---|---|
dock |
target_id (optional) |
Dock with nearest station or specified station |
undock |
— | Undock from current station |
Action Sequencing
When a rule has multiple actions (e.g., undock then rendezvous), they execute
in order. The undock action completes immediately (sends the undock request).
The rendezvous action skips if the ship is still docked (existing guard:
“skip if active maneuver”). On the next tick evaluation, the ship will be
undocked and the rendezvous action will start.
Admin Dashboard: NPC Ship Management
The admin dashboard needs these capabilities:
Spawn NPC Ship
- Admin selects: ship class, name, spawn location (station to dock at)
- Ship spawns docked at the selected station with
is_npc: true - Player ID set to
npc
Configure NPC Automation
- Admin opens the automation rule editor for any ship (including NPC ships)
- Same rule editor UI that players use
- Admin can create, edit, delete rules on NPC ships
- Rules persist in Redis like player rules
NPC Fleet View
- Admin fleet view shows NPC ships with
[NPC]tag - Shows current automation state (active maneuver, docked status, fuel level)
- Admin can select an NPC ship and edit its rules
Admin API
| Method | Path | Description |
|---|---|---|
| POST | /api/admin/npc/ship |
Spawn an NPC ship (docked at station) |
| GET | /api/admin/npc/ships |
List all NPC ships with state |
| DELETE | /api/admin/npc/{ship_id} |
Remove an NPC ship |
| GET | /api/admin/ship/{ship_id}/rules |
Get automation rules for any ship |
| PUT | /api/admin/ship/{ship_id}/rules |
Set automation rules for any ship |
Ship Data Model Extension
Add to ship Redis hash:
is_npc: "true" | "false"
That’s it. No NPC-specific behavior fields — behavior comes from automation rules.
Client Rendering
NPC ships appear as normal ships to all players. The is_npc flag is included
in the WebSocket broadcast so the client can:
- Show an
[NPC]prefix on the ship label - Use a distinct indicator color (e.g., neutral gray or green)
Acceptance Criteria
- Admin can spawn an NPC fast frigate docked at Gateway Station
- Admin can configure automation rules on the NPC ship
- NPC undocks after refueling and dwell time
- Brachistochrone rendezvous to Lunar Gateway completes successfully
- NPC docks at Lunar Gateway, refuels, departs back to Gateway Station
- Cycle repeats indefinitely without intervention
- NPC ship visible to all players with [NPC] label
- NPC ships visible in admin fleet view
- Admin can modify NPC rules at runtime
- NPC ship persists across server restarts
- Maneuver abort → automation re-triggers rendezvous on next rule evaluation
Dependencies
- #748 — Automation dock/undock actions and fuel/docked conditions
- Existing brachistochrone rendezvous system (maneuver_approach.py)
- Existing docking system (docking-and-refueling spec)
- Existing automation engine (automation.py)
Risk: Cross-Body Rendezvous Reliability
The Earth-Luna corridor is a cross-body transfer (ship SOI transitions from Earth to Luna or vice versa). The brachistochrone system handles this via common-parent propagation, but this will be its most sustained test. If rendezvous reliability is insufficient, this issue will surface it.