Xenon 2

Autopilot · write-up

Native navigation environment (ABI 82)

xenondoc/AUTOPILOT_NATIVE_ENVIRONMENT.MD · 8 KB · updated 2026-10-05

ABI 83 now supplies this environment through a C-owned persistent map session; see AUTOPILOT_NATIVE_MAP_SESSION.MD. Python map cells and embedded map metadata are lazy compatibility views.

xenon_autopilot_environment.c now prepares the wall raster, cropped/dilated ship footprints, physical and strategic span graphs, and exact wall queries directly from XapMapState. The shipped-assets path no longer walks Python map cells to select tile patterns, uploads pattern indices, exports free/clearance grids as Python bytes, hashes those bytes and uploads them again to construct C graphs.

The implementation separates raster preparation, ship cropping, graph preparation, snapshot creation and cache ownership. native_environment_reference.py retains the former assembly for comparisons and custom atlases. Set XENON_NATIVE_ENVIRONMENT=0 to select it while retaining the C driver.

Ownership and reusable C interface

  1. Create/seed native map state with xap_map_state_create_level (embedded JSON assets) or xap_map_state_create (an explicit restored map).
  2. Apply captured tile draws through xap_map_state_observe; preserve its existing two-observation destruction proof and static-wall protection.
  3. Create an XapEnvironmentCache, then call xap_environment_cache_prepare with map identity/revision, level, inclusive tile bounds, player collision sprite and integer reserve. The map must remain alive while the cache uses its identity.
  4. Bind the snapshot's handles into mission/scene headers with xap_environment_bind, then call the existing C driver. No JSON, atlas parsing, filesystem access or Python geometry callbacks are required by these C APIs.
  5. Release each returned snapshot with xap_environment_free. Free the cache when its owning pilot/session ends. xap_environment_create also supports an independent snapshot without a cache.

The cache holds at most eight recurring physical footprints. It compares cropped mask content, not sprite identity: equivalent animation frames reuse geometry. All footprints for the same map revision share one reference-counted wall raster. Level 3 and zero-reserve configurations share the physical/strategic graph. Cache eviction or map changes release only cache references; replay-held snapshots keep their immutable geometry alive. Access is serialized, including graph query scratch buffers; this is not an independently concurrent mutation API.

Span topology needs free cells but never reads the clearance scores. Native grid preparation now accepts NULL clearance and skips its writes and both distance passes. The temporary free grid stays in C and is freed after graph construction. Existing reference callers can still request both outputs.

Collision assets

The manual asset generator now includes xenon_autopilot_collision_data.h, derived from shared and all five level SATX/SATL atlas pairs. It preserves level-first, shared-second lookup, deduplicates identical patterns, and stores only low-bit-first alpha rows cropped to the largest wall/ship query (32x27), not BGRA images. Runtime lookup uses sorted numeric sprite identities. Unknown wall sprites retain the conservative solid-tile rule; missing player captures retain the previous rectangle and four-pixel query rounding. The ship crop is unchanged.

Run python xenon_tools/generate_native_assets.py manually after changing assets; --check verifies all six generated outputs. Nothing was added to build-time generation. Custom asset directories/atlas objects and unsupported reserve widths retain the reference assembler instead of silently using incompatible embedded data.

Validation and measurements

Standalone C build, 282 native tests, 67 planner tests, 575 forced-native reference policy tests, and 24 replay tests pass. New tests compare every embedded sprite mask, all five complete rasters, sampled routes/wall probes, actual ship cropping, destruction updates, snapshot lifetimes and cache/raster sharing. A bypass test rejects Python mask/grid/raster preparation on the shipped-assets driving path.

Fresh preparation with the real shared ship collision sprite, CPU pinned and two repeats in reversed order (milliseconds):

Level Reference assembly Native environment
1 9.371 4.180
2 8.201 3.922
3 5.272 1.431
4 10.241 3.992
5 8.681 3.485

This is 52–73% less preparation time, not an equivalent speedup on every frame. Atlas loading and map seeding are outside this measurement. Reproduce with python xenon_tools/benchmark_native_environment.py --pin-cpu --repeats 2. Results: run_logs/native-environment-preparation-ship-0913.json under xenon_tools.

Recorded processing comparisons, two fresh-process reverse-order repeats:

Sample Previous environment Native environment
Level 1, 2367–3367 1.029 ms 1.013 ms
Level 3, 49751–50020 1.518 ms 1.492 ms
Level 5 barriers, 90160–90459 1.490 ms 1.509 ms

All compared decisions match. These small timing differences are roughly neutral; ordinary frames already reuse preparation. Reports are in xenon_tools/run_logs/native-environment-{level1,level3,level5}-0913-final/. Use comparator variants c-environment-old,c to isolate this migration. An initial uncached version rebuilt graphs for recurring sprite frames and regressed Level 1 processing; the bounded C footprint cache fixes that repeated work. No live campaign or WASM profiling was run for this geometry-preserving migration.

Remaining migration

Python still orchestrates map observations, maintains compatibility map cells and world views, initializes its runtime atlas for remaining consumers, and fills small captured driver headers. The new C environment removes geometry preparation from that dependency chain; it does not claim the entire pilot is Python-independent. The next substantial boundary is C-owned observation/world/map orchestration with lazy Python views. Lifecycle, shops, fire scheduling and the final in-memory capture/control adapter remain afterwards. Hatari build integration is unchanged.

Current wall geometry (ABI 106, 2026-10-05)

The earlier animated/cropped ship footprint described above is superseded. Original $387C uses a fixed 25-row footprint from the $3515C table. generate_native_collision_masks.py now extracts that footprint from assets/stram.bin and verifies all 16 shifted copies before emitting ship_wall_rows in the generated header. Sprite alpha remains available for object interaction and terrain rasterization.

xap_environment_create(map, level, first, last, reserve) no longer takes a player sprite. xap_environment_cache_prepare(cache, map, level, first, last, reserve, revision) retains one immutable environment for the current key. Snapshots retain the environment directly; a separate shared-raster owner and eight animation entries are unnecessary. The resident session does not rebuild graphs when the ship tilts. Python inspection mirrors require ABI 106; they are not part of the live resident control loop.

Per-update wall motion rejects every occupied destination. Strategic span segments still validate the complete connector; the old approximate escape-distance exception is removed from the execution path. Actual rollback completion invalidates the failed connector once. See AUTOPILOT_NAVIGATION_REVIEW_20261005.MD for the full-prefix validation and remaining equipment/combat/reward failures.

Manual regeneration remains python xenon_tools/generate_native_assets.py; --check now verifies eight outputs. The legacy preparation benchmark still compares preparation cost, but its two footprints differ; its results no longer establish decision or geometry equivalence. Earlier measurement tables are historical. No phone/WASM timing is claimed.