Files
EscapistsReintroduced/docs/ordinary-game-startup.md

19 KiB
Raw Permalink Blame History

Ordinary game startup validation

Ordinary rounds use progressive mission generation: startup waits for the prison (or crash scene), its initial population/supplies, and the extraction vehicle. The remaining camps, scouting posts, roadblocks and support are prepared after player admission. The server logs separate [generation]: spawn-ready and [generation]: background complete elapsed times. They measure scenario preparation, not engine boot or client loading. Explicit historical Workbench smoke fixtures retain their full-world preparation contract.

tools/headless_game.py prepares a bounded ordinary game run using the installed stable ArmaReforgerSteam.exe, rather than Workbench. It loads either Core or the full Chat dependency chain and the authored successor scenario header. It does not activate any WORKBENCH smoke plugin or add a server flag.

Example, only when other runners have stopped:

python3 tools/headless_game.py --compat /tmp/erri-headless-compat --profile /tmp/erri-game-profile --project core --timeout 180

Use --project chat for the companion dependency chain. The program constructs -addonsDir <successor>/addons -addons <selected addon GUID> -errOrdinaryScenario <core|chat> -profile <private profile> -noBackend -noSound -noSplash -noThrow -disableCrashReporter -logconsole. Engine arguments follow the official Arma Reforger startup parameters. -errOrdinaryScenario is our explicit diagnostic argument, handled by the successor launcher described below. The server-only -server parameter is deliberately absent. The official startup-parameter page was checked again on 2026-09-19: it documents -noSplash for skipping splash screens and -noThrow for disabling error dialogs. Neither option promises to omit layout resource loading or to ignore logged errors.

Isolation

Automated tests must stay hidden. Use the existing headless game, Workbench, and packaging runners; never place test windows on a physical monitor or change the user's Steam launch options. The obsolete right-monitor KWin helper has been removed. Normal Steam play is independent of these runners.

  • Read-only /proc enumeration refuses any existing ArmaReforgerSteam/SteamDiag game instance before launch, including a Wine/Proton launcher command or truncated process name. Unreadable process state fails closed. It does not stop the existing game.
  • The disposable cloned prefix must already exist outside Steam. The same .erri-workbench.lock used by the Workbench runner prevents concurrent use. Existing Wine, Proton, Gamescope and Windows process candidates carrying that prefix also cause refusal. Readable native process metadata excludes unrelated services; ambiguous candidates fail closed. The read-only --inspect-processes mode reports all process blockers without launching, locking, configuring audio or creating profiles. Do not use the actual Steam compatdata prefix or user game profile.
  • The game profile is separate from source, Steam and the prefix tree. An existing directory must have this runner's exact private-profile marker. Unexpected symlinks/addons are rejected; only the installed vanilla data link is created. This does not import the user's game profile or workshop subscription folder.
  • Gamescope uses its headless backend; no main/right-monitor window is requested. -noSound, a unique muted null sink and routing only the run's identified audio streams prevent test output. No default sink or unrelated application stream is changed.
  • Cleanup targets only the launched process group and the locked disposable prefix. Only the null sink module created for this run is unloaded. Cleanup errors are retained as failures; source/log sealing requires confirmed prefix cleanup.

This program never calls Steam account, friend, workshop, login or profile APIs. It does not modify Steam configuration. -noBackend disables the game backend; it is not a claim that the proprietary Steam-enabled executable performs no platform initialization internally.

What constitutes success

A successful run requires all of:

  1. A native Module: Game log with neither WORKBENCH nor ENF_WB in its defines.
  2. The selected native mission header and actual GetSystemsConfig() both match MissionSystems.conf, followed by the normal successor preparation transition phase 0 -> 1, proving the ordinary game loaded and initialized the mission.
  3. Another 15 seconds (configurable 5–120) without native errors, startup failure or leaked ERR SMOKE fixture output.
  4. The launched processes stopped, with unchanged addon bytes and exact final raw-log provenance.

Timeout, process exit before readiness, unexpected multiple log sessions, any native engine/script error or unverified module defines fails. It does not infer success from an executable starting or a blank window.

The ordinary game log may require a disclaimer/menu interaction or may reject offline startup in a particular installed build. This runner does not click past dialogs, change account state, weaken checks, or silently switch to Workbench. Such a run remains incomplete and its captured log should determine the next bounded action.

The source snapshot is captured before process launch and sealed after cleanup, using the existing provenance helpers. runner.json, game-startup-report.json and headless-launch.log accompany the raw game session. The result is game-started, not smoke-completed; existing release qualification therefore cannot count it as a completed escape/restart fixture. Existing archive tooling can retain it as additional evidence, subject to its ordinary error checks and provenance validation.

Current evidence

Thirty source-local tests exercise process refusal (including inaccessible /proc data), prefix/profile separation, exact game arguments and readiness/error gates. They import the runner without launching processes, audio, Steam or the engine. The first host launch is preserved in game-2026-09-19-072609. It failed on a vanilla intro-splash unknown-class error before Game compilation. GameLib defines included ENF_WB, so the executable choice and startup resource path remain under investigation. No ordinary-game startup pass is claimed.

The intended gate is production script compilation/startup validation with WORKBENCH undefined. It is not ordinary player input, a completed escape, manual vehicle use, multiplayer/dedicated-server behavior, an FPS benchmark.

Installed executable selection and first failed attempt

The first Diag attempt, logs_2026-09-19_07-26-09, initialized GameLib with ENF_WB and ENABLE_DIAG. Its vanilla IntroSplashScreen then reported Unknown class SCR_WidgetExportRuleRoot before Game-module compilation completed. The runner retained failure; it did not mask the resource error or count startup.

Read-only installed binary inspection distinguishes three executables:

Executable Bytes SHA-256
ArmaReforgerSteam.exe 37,272,632 1d221a990fa16c78fe02f685a7ba1330be115ca93cd3b641e67e5d3f1b40d9c9
ArmaReforgerSteamDiag.exe 40,060,472 51f941dee28bda7865e2428d7fc92fcbe7c5c7ff666caf642c0ff23c2aced457
ArmaReforger_BE.exe 1,489,648 f1d9117d6c503857fc28ad8be2c828e1ae6124d3055b1fae13ad7e99e3f01d82

The regular and Diag programs are x86-64 PE executables; the separate BE launcher is a much smaller x86 PE. The runner selects the installed regular game directly. It does not invoke the BE launcher or silently fall back to another program.

Diag contains ENF_WB and ENABLE_DIAG strings in the script-initialization constant block; regular contains neither. Both contain the same module/defines log format, so the existing explicit module-evidence gate remains appropriate. Combined with the actual Diag GameLib log, this supports a built-in Diag configuration explanation, not an addon-defined WORKBENCH macro. The regular attempt below confirms its GameLib runtime defines lack WORKBENCH/ENF_WB; a completed Game-module compile is still required. Binary strings alone are not a compilation result.

The installed splash layout contains SCR_WidgetExportRuleRoot at lines15–18, while that class is authored in scripts/Game/UI/Components/SCR_WidgetExportRule.c:82. The log loads the layout after GameLib compilation but before Game completes. This establishes the observed module-order mismatch; it does not prove that regular execution avoids it. No layout override, class stub, error filter, or native acceptance relaxation is included.

The regular executable was attempted in logs_2026-09-19_07-32-31. GameLib compiled without WORKBENCH/ENF_WB. The splash layout still reported the same unknown class at 07:32:32.696 despite -noSplash being present in the logged command. Compiling Game scripts followed at 07:32:32.770, but no completed Module: Game or mission readiness was captured before fail-fast cleanup. This is failed startup evidence, not an ordinary-game compilation pass.

Installed scripts/Game/UI/Components/SCR_WidgetExportRule.c:82 declares SCR_WidgetExportRuleRoot outside any WORKBENCH guard; only its helper methods are guarded later. Thus ordinary-build exclusion of that class is not supported by the source. The observed layout load precedes Game compilation, which is consistent with a module-order issue but does not establish its engine-internal cause. There is no supported alternative splash-bypass flag established by this audit; the existing documented -noSplash remains. No asset stub, installed-resource edit, or log filter is proposed.

Read-only evidence SHA-256: extracted vanilla SCR_WidgetExportRule.c = 3a4b5dc3a8669bf20d903277d249d41ee3ae7e1e74d2c329ed31d435624fa4b5; raw regular-run console.log from logs_2026-09-19_07-32-31 = 20684f6328c7e955d1f08edf16e470e19efc71284856701b43ed31811693536f.

Optional failure diagnostic grace

--failure-grace 30 keeps a failed ordinary run alive for at most 30 seconds after the first observed native/startup error so downstream Game compilation or mission-startup diagnostics can reach the raw log. The default is 0, preserving immediate failure cleanup. Only integer values 0–30 are accepted before any launch or audio mutation.

The first failure stays latched. Repeated errors never reset its timestamp, and later Game compilation/readiness cannot turn the run into a success. The grace expires at the earlier of first failure plus the configured grace or the original absolute run timeout, measured with a monotonic clock. Process exit ends observation immediately. Cleanup, source snapshots, post-stop sealing and raw-log hashing use the same path as ordinary failure.

runner.json records failure_grace_seconds, failure_observed_during_polling and first_failure_elapsed_seconds (relative to the run's monotonic start, or null). game-startup-report.json preserves the final raw error counts and marks an earlier observed failure even if the process later truncated/replaced its log; it never invents error lines. Any later readiness remains failed and does not qualify a release. Safety/preflight failures and cleanup errors do not receive this logging grace.

The twelve additional source-local tests exercise default fail-fast behavior, repeated-error deadlines, readiness before/after error, absolute-timeout truncation, early process exit, log-replacement failure retention, continuous clean settle behavior, exit at the settle boundary, CLI defaults and bound rejection. They use synthetic observations and launch no native process. The extended capture in 074505 confirms completed Game compilation and preserves the subsequent guard-spawn crash.

External crash reporter

The runner adds documented -disableCrashReporter to disable automatic external crash reporting. -noBackend controls backend HTTP communication, and did not prevent the separate reporter in ordinary run logs_2026-09-19_07-45-05: its raw log records Crash reporter started, Sending analytical data and Crash Analytics: OK. The official Crash Report documentation names -disableCrashReporter for stopping automatic sending; the installed regular executable contains that exact parameter. This changes reporting behavior only: local errors, crash logs and failed results remain available. The runner does not use -silentCrashReport or its old name -noCrashDialog, which automatically send reports without a dialog according to the official startup parameters. No test has intentionally induced another crash to validate the option.

Header-based ordinary launch candidate

Direct -world Worlds/ERR_Everon.ent did compile the ordinary Game module (5,728 files without WORKBENCH/ENF_WB) in logs_2026-09-19_07-45-05, created a real local controller and reached the strict identity gate. It then crashed on the first vanilla USSR squad leader spawn. Its world-systems log named no config; the comparable Workbench run explicitly loaded BaseGameModeSystems. MissionSystems.conf inherits BaseGameModeSystems, which inherits ChimeraSystemsConfig including PawnEntitySystem, character animation/damage/control systems and others. Missing configured systems is therefore a grounded cause to investigate, not a proven native crash diagnosis. No identity workaround is included.

The ordinary runner now starts the normal main menu and explicitly requests -errOrdinaryScenario core or chat. Core owns the opt-in ERR_OrdinaryScenarioLaunch.c; Chat adds only its own header/addon selection override, preserving the dependency direction. Both are absent from WORKBENCH compilation and inert without the explicit argument. The launcher queues one attempt per game instance, validates the selected installed successor header/addon pair and only calls the native transition from an idle main menu. Active worlds and pending native transitions are never replaced. World cleanup cancels an outstanding callback. No click, user identity, audit callback or backend state is synthesized.

The exact installed API is GameStateTransitions.RequestScenarioChangeTransition(ResourceName missionOrWorld, ResourceName worldSystemsConfig, string addonList): its documentation accepts a mission header or world. Vanilla game.c:1246 uses it in PlayGameConfig. Both current fixture selectors pass {C1E20667DCE324ED}Missions/ERR_Everon.conf after retirement of the duplicate Base header; both specify {C50579A2EC48E8EF}Configs/Systems/MissionSystems.conf. Once a successor world starts, the diagnostic only inspects its active header and actual GetSystemsConfig(); the runner requires that verification plus ordinary module/phase/settle evidence. Existing splash errors still permanently fail the run, even if downstream header verification succeeds.

This uses the documented native transition API, not an invented -scenario engine parameter. The official -worldSystemsConfig startup parameter is marked Diag-only, so it is not assumed to configure the regular executable. Native compilation and actual header transition are pending; failure to reach an idle main menu is retained as a failed diagnostic, without retries that could replace gameplay.

The runner now additionally requires a matching local-participant marker after normal finalized admission: the actual local controller must own the living body, the canonical roster must accept it, and the mission must be in PRISON. Header/world readiness alone can no longer pass while player admission is absent. This new observation is gated by the ordinary diagnostic flag and never creates a body or identity. Its ordinary native compilation is pending.

Optional ordinary prisoner view

The explicit -errOrdinaryScenario core|chat -errOrdinaryScreenshot 1 combination requests one screenshot three seconds after genuine finalized local prisoner admission. The runner exposes this as --capture-prison-view for loose successor startup; packed and vanilla-control runs refuse it. The request is absent from Workbench compilation and inert without both diagnostic arguments. It does not select a camera, inject input, move an entity or change presentation, so a captured menu, loading overlay or unexpected viewpoint is a finding to investigate rather than something the helper hides.

Before requesting System.MakeScreenshot("$logs:err-ordinary-prison"), the helper revalidates the same current world/mode, active prison phase, living actor, canonical roster-life/account, local controller and player-manager binding. It requires the exact opt-in value 1 and a non-console authoritative game. The owned delayed callback is removed on mission stop and by the existing native OnBeforeWorldCleanup hook; the per-world attempt latch prevents a second admission notification from requesting another capture. Invalidated admission cancels without retry. A new world resets the latch.

tests/test_ordinary_screenshot.py executes the helper's actual gate, queue, validation, capture and cleanup methods through adapters, including replaced controllers/bodies/lives, death, phase/world changes and late callbacks. This verifies source behavior only. The native capture call and actual image must still be checked in the ordinary game; a screenshot alone does not qualify manual escape, multiplayer or performance. Preserve the image with that run's raw logs and source provenance.

121730 passes ordinary Chat startup and the optional capture. The unaltered player view shows the prisoner inside the authored walls with the correct escape objective and instructions. The exact native BMP is retained beside a documented lossless PNG conversion. The image also exposed tall wheat inside the yard; the first bounded decal candidate in 122353 clears only a small central patch and is not yet full-yard treatment. Neither capture supplies player-input or full-route acceptance.

125906 integrated startup passes after the admission-budget, interaction-feedback, optional aircraft-target and stock-scale yard changes. The native player view remains correct. The scale-ten vanilla decal clears a larger irregular patch while wheat remains near and within parts of the enclosure; complete yard clearance is not claimed. This is ordinary-game startup and initial-view evidence only.

Roadblock props remain replicated independently of player distance so an admin viewing the island through Game Master can see the same barriers as nearby players. This is limited to the 18 props per post (at most 540); guard and vehicle streaming is unchanged. A post is counted only after all 18 props have valid replication nodes. Local Workbench validation does not by itself prove remote-client visibility.