Autopilot · write-up
Native driving coordinator (ABI 81)
ABI 82 supersedes the host geometry preparation described below: Native navigation environment. C now builds the raster, ship footprints, graphs and wall queries from native map cells and generated collision data; the host still orchestrates observations and compatibility views.
Embedded data regeneration is documented in AUTOPILOT_GENERATED_ASSETS.MD. Run the generator manually; builds consume the checked-in C outputs.
The native/span path now calls xap_driver_step instead of constructing Python
PredictionService, Mission, ManeuverPlanner, evaluation results and retained
action tuples. The final small Python Decision remains the existing transport
interface; it does not participate in planning.
Ownership and structure
xenon_autopilot_driver.cowns mission state and retained-plan state. Its stages prepare the player/equipment, select sources, choose the level mission, assemble a shared scene and evaluate controls. Existing level modules remain separate.xenon_autopilot_driver_selection.cselects contact hazards and conservatively culls distant formations through shared native predictions. Source classification, target/blocker selection and collision/combat consumers reuse the same selection.xenon_autopilot_driver_spawns.cinterprets captured pending Level 3 scripts before allocation. It creates six delayed native paths in the shared point pool, without six synthetic Python world objects or a fallback to the Python planner.native_driver_environment.pysupplies existing native map/graph/wall-query handles. It prepares them only when map identity/revision, bounds, ship sprite or navigation configuration changes. Stable frames no longer repeat full-grid conversion/hash lookups, footprint preparation or graph selection.native_driver.pypacks capture fields, invokes the driver, and provides separate explicit inspection functions. It does not derive trajectories or score candidates.
Equipment input contains captured offsets for the game's two wing slots. C derives the primary, Laser and Cannon collision lanes using named constants. Current player geometry comes from the canonical native world; camera state is prepared from captured telemetry. Pickup protection uses numeric codes and retains the first-half Level 3 Rear exception. Persistent map destruction evidence remains authoritative.
Driving and inspection
Create a driver with xap_driver_create, then call xap_driver_step for each active
observation. Inputs borrow a decoded/prepared XapWorld, persistent map, navigation
graphs, wall environment, equipment, camera telemetry, fire schedule and pending
dispatcher captures. The mission-input player/prediction/mount fields are derived by
the coordinator; external callers need not fill them. Output contains movement mask,
fire permission, verification status, numeric tactic/contact and compact work counts.
The fire pulse/transport adapter still applies the actual fire button.
xap_driver_mission, xap_driver_decision, xap_driver_scene and related accessors
are optional inspection interfaces. Ordinary driving does not call them. Live traces
request inspection before serialization; replay requests it for displayed/saved
frames. The formation overlay reads cached C paths only when requested. Replay no
longer computes the obsolete Python target ranking for each native-driven frame;
its native view identifies the actual selected mission target.
An explicit xap_driver_clone copies bounded mission/retention state and shares
immutable observation inspection storage. Advancing either driver creates a fresh
observation. Losing trials and prefix-search storage are released after the winner
is chosen, so replay snapshots do not retain the entire search. Hosts must serialize
access to a driver/shared graph owner; these are not concurrent mutation APIs.
World/environment owners stay alive through their consumers. Saved inspection geometry
can be read after a checkpoint advances, but must not be reused for fresh evaluation.
In-memory replay snapshots clone control state and rebind diagnostic identities to their copied world. On-disk snapshot restore still resets native control history and re-infers mission state, as the previous native-mission path did.
Compatibility and remaining Python
The path is enabled for the C kernel with span navigation on all five levels.
XENON_NATIVE_DRIVER=0 selects the previous Python coordinator with C mission and
evaluation kernels. XENON_NATIVE_MISSIONS=0 additionally selects Python mission
tactics. The Python kernel and non-span backends remain available. The benchmark
variant c-driver-old isolates this migration from the preceding committed driver.
This is not yet the complete independently running game autopilot. Python still transports/decodes protocol capture envelopes into the native observation interface, maintains compatibility world/map views, initializes the map/raster/graph environment, and handles absent-player frames, shops, transitions, fire scheduling and recording. The C driver consumes the prepared native world; it does not itself call the TCP protocol parser or own all host map initialization. Moving those remaining host responsibilities is separate work. No Hatari build integration or WASM profiling was performed here.
Validation and measured effect
Standalone native build passes. Focused suites: 275 native, 67 planner, 575 forced-native reference-policy, 24 replay, 7 world-decoder and 37 shop tests (985). New tests prohibit the removed Python preparation/planner/weapon-lane calls, verify all five level dispatches, explicit inspection, checkpoint isolation, pending swarm delays, and environment reuse/invalidation. A recorded backward/forward cached seek also preserved controls and all 57 winning-path points.
Fresh-process, CPU-pinned comparisons use two repeats with reversed execution order. Both variants already use C mission and evaluation kernels; these are additional improvements over the previous commit, not comparisons against the original Python autopilot. The metric is recorded processing time, excluding live TCP/video capture.
| Sample | Previous coordinator | C coordinator | Reduction |
|---|---|---|---|
| Level 1, 2367–3367 | 1.750 ms | 1.014 ms | 42.1% |
| Level 2, 32577–33537 | 2.045 ms | 1.358 ms | 33.6% |
| Level 3, 49751–50020 | 3.223 ms | 1.518 ms | 52.9% |
| Level 4, 63486–64385 | 3.952 ms | 1.600 ms | 59.5% |
| Level 5 barriers, 90160–90459 | 2.268 ms | 1.513 ms | 33.3% |
| Level 5 tank, 91740–92130 | 3.702 ms | 2.705 ms | 26.9% |
Reports live in xenon_tools/run_logs/native-driver-{level1,level2,level3,level4,barriers,tank}-0913-final/comparison.json.
Level 1 produced identical compared decisions. Other samples differ and the comparator
returns its decision-difference error after writing the report. The new culling uses
a conservative whole-path bound instead of the Python four-frame sampling loop;
native retention and source preparation also remove dependence on Python bookkeeping.
Timing alone does not establish gameplay equivalence.
Bounded live recordings, with the same name inside their .validation directories:
native-driver-level2-live-0913-a: frames 33362–33961, shield 39→39, zero lives lost, three pickups, score +6850. Preparation/hold/progression through homing waves.native-driver-level1-shell-live-0913-a: frames 7171–7770, shield 39→39, zero lives lost, one pickup, score +4900, three wall shooters reported destroyed. This exercises the approach and shell tactics, not complete boss/level victory.
The previously documented Level 4 pocket and Level 5 barrier/tank gameplay failures are not declared fixed by this migration. No whole-campaign acceptance is claimed.