19 KiB
Finite physical convoy controller
Independent adaptation of owned escapists-ai/Scripts/Game/EscapistsAI/EAI_SupplyConvoys.c, SHA-256 a896fdacfd9c0f2db52e588642623545a3a5d6e8041fb72000a68e720fc2b7a5. Reused responsibilities are the six-vehicle catalog/order, native seat creation, independent native crew groups, finite cargo and owned-waypoint release. Original Escapists/ScrtCore helpers, original game mode hooks and EAI_GroupLookup are excluded. Native BaseCompartmentSlot.SpawnCharacterInCompartment, group vehicle manager and waypoint APIs replace those dependencies.
The round owns one ERR_ConvoyPool(mode,maxConvoys) and one ERR_ConvoyService(mode,pool). Reserve a unique authored source ID; dispatch its canonical one-use receipt with six authored positions/angles and a sealed, nonlooping Core ERR_ForceRoute. Resource, terrain/water/obstacle, faction and shared budget validation precede consumption. Consumption precedes native entity creation. Partial native startup consumes the slot and preserves every successfully created group, vehicle and actor; there is no refund or automatic retry/replacement.
The exact composition is PKM UAZ, ammunition Ural, troop Ural, PKM UAZ, BMP-1, PKM UAZ. It allocates 19 bodies: three UAZ driver/gunner pairs, one ammunition-truck driver, troop-truck driver plus eight infantry, and BMP driver/gunner/commander. Capacity failure does not shrink this plan. The selected own memberless USSR group and vanilla character catalog are explicit; other factions require a reviewed catalog. BMP driver, gunner and commander seat declarations were independently inspected in the installed WCS PAK; convoy-bmp-seat-audit.json records resource-byte hashes and declarations without redistributing assets.
Outstanding receipts plus physical, noneliminated Core ledger strength must fit 60 bodies; ledger records plus outstanding convoy groups must fit 128 formations. The same exact group moves from outstanding budget to its CONVOY record before normal mode registration. A 40-body world can reserve one full 19-body convoy, giving 59. Use one allocator for the round; creating independent pools would not share outstanding reservations. The fixed convoy limit and consumed source IDs survive losses within that pool.
The controller waits up to 30 seconds for exact original native crew membership and vehicle registration. Once ready it issues native move waypoints along the supplied finite road route. Each vehicle retains one owned waypoint at a time; arrival advances once, a ten-minute leg deadline releases stalled orders. Death, captured/reparented crew, destroyed vehicles and explicit Stop release orders without deleting physical entities. A player entering any convoy vehicle or crew releases the convoy task. Native combat may interrupt movement. No perception information or reinforcements are invented here.
The ammunition truck receives one bounded pass of eight AK74 and 48 matching magazines. Native capacity or failed operations may reduce actual cargo. Accepted asynchronous operations are never repeated or replenished. Status separates native insertion completions, failures and pending callbacks; completions are not an inventory snapshot after looting. Native accepted insertions cannot be cancelled by these callbacks, including after a controller Stop.
This is a partial convoy migration. HQ now exposes opt-in preparation/dispatch for the authored supply seed; native vehicle driving and physical cargo evidence remain separate requirements. Original two-team infantry dismount/flank/reboard tactics, delivery/unloading, rearming, route/base selection and Cylon gunner specialization are not claimed by this slice. No autonomous convoy spawn timer or unsupported convoy setting is installed.
Tests execute actual shared-budget, dispatch, seat allocation, readiness admission, cargo request and waypoint lifecycle bodies against native API doubles. They prove bounded/idempotent policy and partial-failure ownership; they do not prove native seats, AI driving or multiplayer replication.
Road preparation and clearance
ERR_ConvoyRoadPlan.Build(seed, out positions, out angles, out route) selects deterministically among actual native roads within a 500m query. It refuses more than 128 road candidates, widths below 4m, polylines over 1024 points, and roads shorter than 390m. Each road gets at most 33 candidate formations: the preferred projection followed by offsets +35m, −35m, +70m, −70m, up to ±560m along that same polyline. Offsets outside the valid start interval are refused rather than clamped into duplicate formations. Every one of the six starts and the sampled formation center must lie within 500m of the explicit seed. Eligible candidates are ranked by formation-center distance and deterministic geometry ties before expensive clearance queries when a better clear candidate already exists. This bounded scan can find clear alternatives to an obstructed initial projection; it is not an exhaustive search of all possible formations.
Six starts remain 35m apart along the actual polyline with a 15m rear margin and at least 200m forward route; every intermediate bend is retained, with refusal at the Core route's 64-point limit. Tight bends that place any two starts less than 18m apart are rejected. Native terrain grounding preserves the road XZ coordinates. There is no random, offroad or scenery-removal fallback.
Each oriented start checks nine terrain/water samples across a conservative 4m by 9m footprint. Terrain must be above 0.3m, vary by no more than 0.75m across the footprint, and agree with the starting altitude. The enclosing volume extends from 0.05m above the lowest grounded sample to 3.5m above the highest. A filled native TraceBox checks that volume with a 0.01m upward sweep against entity and ocean geometry; a nonfinite result or trace fraction below one refuses placement. An entity AABB query remains bounded diagnostic context only: overlapping bounding boxes or its visit cap no longer veto a geometrically clear footprint. These admission rules do not guarantee that native drivers can negotiate the whole road.
The focused road/placement tests execute the installed method bodies with geometry and native API doubles. They cover exact minimum geometry, reversed direction, offset ordering/refusal, locality of all selected starts, an obstruction requiring an alternative formation, degenerate and dense polylines, bend retention, tight-hairpin rejection, deterministic ties, rotated footprint bounds, terrain/water rejection and filled-volume collision results. Native-query doubles distinguish a tree's overlapping broad bounding box from an actual blocking shape.
The first native convoy run compiled all scripts but refused the authored supply seed before spawning entities (native-2026-09-20-020706-convoy-road-refusal). Road diagnostics subsequently found valid long roads. The placement diagnostic archive native-2026-09-20-021626-convoy-placement-diagnostic identified broad tree bounding boxes 6–12m outside the pavement and overhead power-line bounds as false positives; actual sampled road terrain spans were 0.10–0.73m. That evidence motivated the filled-geometry check without relaxing terrain limits. The later crew/cargo run below validates selection and a real-vehicle collision positive control; full convoy driving remains unproved.
Preventing queued default crew
Native readiness archive native-2026-09-20-023545-convoy-readiness-regression exposed at least six native agents in every group, including vehicles intended to have only one, two or three crew. The vanilla faction group Group_USSR_Base.et authors six soldier slots (inspected resource SHA-256 77a7c5caee98e13ba45204d1084636f4bf50f9414e2b048e43a60e1966535e96), and native SCR_AIGroup.EOnInit queues those slots asynchronously. Checking that group for zero agents immediately after spawn did not exclude its pending default allocation.
The convoy now uses independently authored {7A968AB297475FA7}Prefabs/ERR/ConvoyCrew.et, inheriting the memberless vanilla {000CD338713F2B5A}Prefabs/AI/Groups/Group_Base.et (inspected SHA-256 a8defc28500877cdd215f9c41d1eb003359f9455b1b063c5b8f15c644958c889). It declares USSR faction, disables immediate spawning and has no authored slots before native initialization. A strict runtime template guard checks all three conditions—no immediate spawn, no agents and no authored slots—before finite seat allocation. It neither deletes unexpected soldiers nor cancels another group's spawn queue. Actual-method and resource regressions pass. The subsequent engine run confirms exact post-initialization membership as described below.
Native crew and cargo checkpoint
02:40:35 crew/cargo run passed 109 assertions before a deliberate interruption, with no script/runtime failures. All six original vehicles retained exactly 2/1/9/2/3/2 native seated members, totaling nineteen, and six new Core ledger records. The actual truck inventory contained eight new AK74 rifles and at least forty-eight matching magazines after the single finite cargo batch. Repeated dispatch and a second reservation were rejected. A filled collision query against the actual lead UAZ returned a blocking fraction of zero, while road placement had accepted the empty formation positions.
The lead drove approximately 51.8m, but the minimum vehicle displacement stalled at 8.0m. This does not satisfy the fixture requirement of every vehicle moving20m and the lead100m. The run was interrupted through the runner's cleanup handler after sustained stagnation; it has no completed smoke round. Four external localization errors remain. Source and external files were unchanged and owned process cleanup was confirmed. Per-vehicle driving diagnosis is the next step; this checkpoint does not qualify delivery, combat, unloading or multiplayer.
Matching native waypoint completion
02:46:43 movement diagnostics
identified the stall: the lead, troop truck and BMP had no current native waypoint
and had switched to idle, while their retained owned waypoints still reported
native group completion. Vehicle-origin distances were35.5m,38.5m and37.7m.
The controller's separate vehicle-centre test against35m therefore missed valid
native completion. It now uses the owned waypoint's
IsWithinCompletionRadius(Group), matching the stock group waypoint decorator.
The authored35m radius, original-crew validation, finite route and one-owned-order
rules stay in place. Focused actual-method regression verifies progression after
native removal, exactly one next waypoint and no duplicate advancement; updated
native driving validation is recorded below.
Completed native driving check
02:50:35 convoy driving completes one scripted round with181 passed assertions and no script/runtime failures. All six original vehicles drove at least20m and the lead over100m, without fixture movement. Exact original seated membership, all six Core records, the finite eight-rifle/48-magazine cargo batch and repeated-dispatch rejection were verified again. The result includes subsequent native prisoner death, spectator transition and mission cleanup. Source/external inputs stayed unchanged and hidden, muted process cleanup was confirmed.
The same four external string-table errors keep the strict native qualifier failed. This single short road run establishes the initial physical controller; it does not prove full-route reliability, native combat/dismount/reboarding, logistics delivery/unloading, multiplayer or FPS improvements.
Delivered HQ mounted-cover follow-up
This follow-up adds per-vehicle HOLD/RESUME travel commands to the existing finite convoy. It does not change the six-vehicle receipt, nineteen original crew, finite initial cargo or opt-in manual dispatch. The earlier native driving archive above predates these combat commands.
HQ planning uses two delivered inputs: a living, nonclosed original crew's own status position no older than 180 seconds, and a positive sighting less than 60 seconds old within 400 m of that reported position. Exactly 400 m and exactly 180 seconds are accepted; exactly 60 seconds is no longer a planner contact. The executor permits a HOLD report age up to 60 seconds, but HQ rechecks its stricter current-contact rule at delivery. Neither the planner nor a silent crew substitutes a live vehicle or hidden enemy position for those reports. Body/distress beliefs do not become convoy fire targets.
Each original crew uses its existing shared HQ downlink. A queued combat command contains the convoy source ID, original group, vehicle index, monotonically increasing command ID, originating sighting ID/time, issue time and an expiry at most 30 seconds later. Queuing does not stop travel. Only successful physical radio delivery can reach the executor; it rechecks current contact evidence, own-status freshness, canonical consumed receipt, matching physical Core record and exact original crew. Foreign, duplicate or expired commands cannot replace the current order. A newer nearby sighting still justifies an in-flight HOLD, so reports arriving faster than the downlink cannot starve cover delivery. A superseded RESUME is rejected.
An accepted HOLD removes only that vehicle group's owned move waypoint and preserves its route index. A newer delivered sighting can refresh the held lineage without repeatedly clearing waypoints. A RESUME is considered only after 60 seconds since the held sighting, with fresh own-position status and no current qualifying contact. It must match the held sighting ID/time. New contact arriving while the downlink travels invalidates an older RESUME; a failed HOLD refresh cannot accidentally authorize it. Missing radio or stale own status retains the current travel/hold state. There is no independent timeout that silently resumes a held vehicle. A successful RESUME creates one native move waypoint at the preserved route index. Failed native recreation consumes that command ID and releases the vehicle's order instead of retrying the same command.
At admission, ConvoyService
calls the native utility.AddUsableVehicle(usage) helper after vehicle-manager
admission. This registers the native deletion/damage callbacks and mounted combat
activity omitted by raw manager insertion alone. Native perception, weapon aiming
and firing remain the engine's responsibility. HOLD supplies no target coordinates
to a gunner and does not prove that the gunner fires or suppresses a player.
This is mounted cover, not migrated infantry dismount/flank/reboard tactics.
Player occupation of any convoy vehicle or crew still stops the whole task. Release clears owned orders and temporary forced detail while leaving vehicles, weapons, cargo, casualties and survivors physical. HOLD/RESUME introduces no new crew/vehicle spawn, ammunition grant, cargo refill or replacement receipt. The separate small-arms status model does not estimate mounted vehicle ammunition or provide convoy rearming.
Combat executor tests and HQ radio/planner tests execute the actual methods against boundary doubles. They cover freshness, lineage/replay, shared pending downlinks, changed evidence in transit, owned waypoint hold/resume, original crew/ledger identity, capture and failed recreation. These are policy regressions, not native mounted firing or multiplayer evidence.
The 04:11:50 native driving recheck compiles this follow-up and completes one round with 181 assertions and zero script/runtime failures. All six vehicles move at least 20 m, the lead exceeds 100 m, and the original nineteen seat occupants, six records and finite truck cargo remain intact. This includes the native mounted-combat registration but does not exercise a combat HOLD/RESUME or prove firing. Those transitions still need a direct native scenario. Source and six external dependencies stayed unchanged, and hidden/muted process cleanup was confirmed. Four external localization errors keep strict native qualification failed. Full-route, dismount/flank/reboard, unloading, multiplayer and FPS work remain outstanding.
Cover test and seat-retention diagnostic
The opt-in --smoke convoy --convoy-cover --rounds 1 --timeout 900 test first requires the existing physical driving/crew/cargo proof, then moves only the canonical local prisoner beside the original lead vehicle. It observes genuine perception, completed uplink, HQ HOLD, completed downlink and owned-waypoint removal, conceals that same prisoner at a distant authored site, and waits for ordinary evidence expiry and delivered RESUME followed by 20 m of physical travel. Temporary player damage protection is restored on success, refusal or shutdown. No AI, ammunition, reports, radio routes or production timers are created or altered by the cover arrangement. The cover-only smoke timeout is 840 seconds; ordinary convoy timing remains unchanged.
05:09:06 diagnostic compiled the current addon sources and passed 170 assertions, but failed the final driving-stage population check: original crew member 18, the final UAZ gunner, failed the combined conscious/original-seat/identity assertion. Exact group membership still matched the six-vehicle plan. That combined failure alone cannot distinguish unconsciousness, a seat switch, dismount or another predicate; failure-only diagnostics now record each condition without changing the assertion. The cover arrangement never started; this run does not validate HOLD/RESUME. The failure is retained without weakening the seat check. Four installed RHS/WCS localization errors also remain; private cleanup and unchanged launch sources were confirmed.
test_native_convoy_cover_probe.py executes the fixture's observation, snapshot, delivery and cleanup methods against native doubles, including rejected/failed radio routes, unapplied orders, unchanged HOLD refresh measurement, exact resumed route index, quiet age and damage restoration. Runner refusals occur before launch for an incompatible smoke mode or insufficient cover timeout. These policy tests do not replace the still-pending native cover sequence.
The 20 September 05:15:05 convoy cover run passed the baseline six-vehicle driving, original crew/seat and cargo assertions. After arranging the existing prisoner beside the lead vehicle, it captured no qualifying visual reports and failed the combined physical-force/player invariant about 34 seconds later. It therefore does not establish native HOLD/RESUME behavior, nor identify a production defect. The retained logs do not distinguish an ordinary completed route from a released vehicle, crew-state change, controller change or physical-force-list difference. The lead route advanced from index14 to18, but that alone does not establish task completion: production ends the task only when all six orders have arrived or been released, and the fixture allows an individual arrived vehicle. Failure-only diagnostics are now included for a future run; no additional convoy test was launched at this checkpoint.