8.3 KiB
Optional ordinary-game input observation
ERR_OrdinaryInputObserver.c is an ordinary-game-only, read-only diagnostic. It does nothing unless the existing errOrdinaryScenario=core or chat option and errOrdinaryInputObserve=<nonce> are present. The nonce must contain 1–32 ASCII letters/digits; path punctuation, whitespace and other characters are refused. The observer does not generate input, open/close inventory, move a prisoner, adjust a camera, grant protection or change gameplay. Native compilation and one bounded sampler lifecycle are now evidenced by the 160522 ordinary Chat run. No input was sent; neither that run nor the source-policy tests establishes actual input delivery.
The request starts only after genuine finalized local admission. It pins the exact current mode, native world, local controller, connection ID, controlled body, native character controller, canonical roster life and existing account UUID. Every sample rechecks those bindings, active prison phase and the original conscious living body. The account and identity references remain private and are never logged. Loss of ownership, life, world or phase cancels the request permanently. Native movement-control disablement alone does not invalidate it: inventory UI may legitimately disable ordinary movement while the same body remains conscious.
One owned callback is queued at a time, at 100 ms intervals. At each callback the process tick clock enforces a strict 45-second window from queueing, independently of world time; 450 samples is a second hard bound. Clock reversal cancels/finishes observation. As with any game call queue, a paused or stalled engine cannot execute the callback exactly at its deadline: on resumption it records no further input sample past that real-time bound. Mission stop and world cleanup remove the owned callback and subscription. The process-wide one-attempt latch survives cleanup and prevents another round or re-admission silently starting a new experiment.
READY requires two continuous real seconds with inventory absent, input and CharacterForward near zero, velocity at most 0.05 m/s and no more than 0.05 m positional drift. Gaps over 500 ms reset that baseline. These tolerances qualify a stationary baseline only; they never classify later movement as successful. Every recorded SAMPLE includes the validated nonce, sample index, process/world clocks, actual origin, native CharacterForward value, character movement-input vector, native velocity and inventory visibility. A later wrapper must correlate those observations with separately authorized input timing. Displacement alone is not evidence of walking, and a blocked movement attempt is not a success.
Inventory observation requires the actual SCR_InventoryMenuUI, its character controller matching the pinned body's component, a visible root and native top-menu agreement. Only an open after READY counts. The subsequent absence of that menu counts as INVENTORY_CLOSED, with the original admission still valid. A replacement menu, mismatched body, hidden/incomplete root or a second opening cancels rather than manufacturing a close/reopen sequence. The native top-menu API excludes dialogs; this diagnostic does not claim that no modal overlay exists.
Optional errOrdinaryInputScreenshots=1 requests at most three captures, on READY, first observed open and first observed close. Paths are fixed-format $logs:err-input-<nonce>-baseline, -open and -closed. A capture request is logged separately and does not prove the file was written or readable; an external archive must verify the actual images. No camera changes accompany capture.
Integrated hooks and runner
The existing ordinary-only ERR_OrdinaryScenarioLaunch.c queues this observer after its genuine validated PlayerSpawned admission and clears it in OnBeforeWorldCleanup, before the native superclass. Both calls remain inside the existing #ifndef WORKBENCH guard; no extra spawn override is installed.
Use headless_game.py --observe-player-input --settle 50 with loose Core or Chat. The runner supplies its fresh run ID as the nonce and enables the bounded captures. Control/packed modes and shorter settling windows are refused before launch setup. After cleanup it validates the exact nonce, ordered finite samples and clocks, QUEUED/READY/FINISHED lifecycle and any inventory/capture transitions. Missing or cancelled observation fails the opt-in diagnostic, while prior native/display/source failures remain failures. This qualifies a sampler lifecycle only; it cannot by itself prove input delivery or inventory usability. Actual image files require separate inspection.
Installed API evidence and tests
The implementation reads installed generated CharacterControllerComponent.GetMovementInput, GetVelocity and IsUnconscious; the vanilla character controller already reads local InputManager.GetActionValue. Installed SCR_InventoryMenuUI.GetInventoryMenu returns the actual inventory menu and GetCharacterController returns its bound native character controller. SCR_StringHelper.Filter demonstrates native string indexing and Contains for the nonce whitelist. The existing successor ordinary screenshot request establishes System.MakeScreenshot and native call-queue lifecycle usage. The separate 160522 ordinary run supplies native compilation and sampler-lifecycle evidence; these API references alone do not.
tests/test_ordinary_input_observer.py executes the actual nonce/time/baseline policies, admission checks, queue/sample/menu/capture/cleanup methods with explicit native read-boundary adapters. It covers changed controllers, bodies, roster lives and accounts, mode/world changes, unconsciousness, disabled/invalid flags, menu replacement and root ownership, closed/open/closed sequencing, repeated callbacks, both time bounds, clock reversal, screenshot limits, cancellation and the retained one-attempt latch. Static checks reject input/menu/actor/camera mutators and identity fields in logging. None of these tests claims native user input, human playtesting, multiplayer, FPS improvement or a completed escape route.
Native sampler result and separate display failure
The 160522 console contains the exact nonce's QUEUED, READY and FINISHED lifecycle without CANCELLED. READY followed the stationary baseline, and 391 samples were recorded before FINISHED observation-bound at 45.014 seconds after queueing. The runner parser reports sampler_complete: true, with one baseline capture request and no observed inventory open or close. No movement or inventory input was generated, so this proves the bounded read-only observer ran, not that player controls or inventory interactions succeeded. A logged screenshot request remains distinct from verified image content.
The overall run result remains display-probe-incomplete because private-display game-window ownership was not verified. Its ordinary startup report has a genuine local participant, the Chat header, normal game modules and zero script/runtime or engine errors; cleanup was confirmed and sources were unchanged. Successful sampler evidence does not erase the independent display-verification failure, authorize later input, or qualify a manual playtest.
The subsequent ordinary run passes overall: 398 samples over 45.096 seconds, a canonical prisoner, verified private game-window ownership and mapped existing focus, zero captured engine errors, and verified idle cleanup. No external input is sent and neither inventory transition is observed. The native baseline screenshot shows the authored prison and readable starting objective. This supersedes the display-verification failure only for the new run; earlier evidence remains unchanged.
Later real keyboard diagnostics observe movement and exact inventory transitions, but the native runs fail on two stock-inventory slot errors. The helper sends inputs; this observer remains read-only. The third diagnostic's sampler ends early under failure grace, so its observed transitions are not promoted to complete sampler or clean runtime acceptance. Its open-labelled screenshot shows the prior world frame and cannot establish inventory visibility.