# Track note: core (the shared core task, 2026-10-04) Written by the Coder of the core task. `Docs/STATUS.md` has the user-facing facts (commands, APIs, conventions); this note keeps what does not belong there: where the build departs from DESIGN_UE.md, what was guessed, what was added beyond the brief, what was not run, and what the next tracks should know. The Administrator folds what matters into STATUS.md when merging; nobody else edits STATUS.md. ## Where this build departs from DESIGN_UE.md, and why | Design says | Built | Why | |---|---|---| | `FDescentIntent` has `Look` (unit unspecified) | `Look` is an angular **rate, degrees per second** (X yaw, right positive; Y pitch, up positive) | A debug override *holds* an intent for a sim duration (section 9.2). A held per-step delta would turn the view endlessly; a rate holds. The controller turns a frame's mouse delta into a rate by dividing by that frame's dt. | | `Descent.Player.Intent fwd right up lookYawDeg lookPitchDeg seconds ...` | Arguments 4 and 5 are look **rates in deg/s** (same reason). The command also sets `bJump` when up > 0.5 and `bDown` when up < -0.5 | Up/down is the jump/crouch key pair as well as the swim axis (section 5.7 table). | | Section 9.3 lists `Descent.Player.*` commands under M2 | `Descent.Player.Intent` lives in `Debug/DescentCommands_Intent.cpp`, not in a player commands file | It belongs to the sim's intent latch, which exists now. The player track creates `DescentCommands_Player.cpp` for Place / MoveTo / Look / Use / Set / Give / Mode and must not define Intent again. | | `r.GenerateMeshDistanceFields=True` was set in M0 | Removed from `DefaultEngine.ini` | Not in the section 1.1 list; it existed only for Lumen's software tracing. Nothing here uses distance fields. | | `S.WaitSim`, `S.FastForward`, `S.Expect`, `S.ExpectNear` | As specified. `ExpectNear` takes a value *function* (the number is known only at run time) and also a plain-`double` overload | A constant checked against a constant is useless, but another Coder may write it that way. | | `Descent.ShotRegion` | Built, plus `Descent.ShotRing cx cy r0 r1` | Same table row; the `look_bloom` scenario needs it and it is the same code. | | Section 1.4: `Step(dt)` / `LateStep(dt)` | Callbacks receive an `FDescentSimFrame` (world, dt, sim time, step index, `bFastForward`) rather than a bare dt | Lets a system skip cosmetics while fast-forwarding and know the index without a second API; adding a field later changes no signature. | | Section 1.4 tick prerequisite | `UDescentSimSubsystem::GetSimTickFunction()` returns the tick function; the character (M2) calls `AddPrerequisite(Sim, Sim->GetSimTickFunction())` | The character does not exist yet, so the prerequisite is not wired. | | `ADescentGameMode::StartPlay` runs the boot sequence | It calls `Super::StartPlay()` **first**, then runs the registry | Every actor a boot step spawns is then begun at once, and the next step can rely on it. | | The `ui` state section | `ui` is assembled from **parts** (`FDescentStatePartRegistrar`); this task registers `ui.hud` | A section was one provider; the design's `ui` is written by several files. Whole-section providers still work. | | Showcase rig lived in the map | `ADescentShowcaseRig` owns its own fog and fixed exposure and is spawned by `kazah_showcase`, `kazah_closeups` and `smoke` | The map holds only a PlayerStart (section 1.1). | ## Added beyond the brief (small, and each exists to keep tracks out of shared files) * `Core/DescentGameClasses.h` (`DESCENT_REGISTER_GAME_CLASS(Pawn, 100, ADescentCharacter)`): the game mode no longer names its pawn and controller; the track that owns a class registers it with a priority, highest wins. Otherwise the M2 track would have edited `DescentGameMode.cpp`. * `Core/DescentWorldSubsystem.h`: base class of all world subsystems, which exist in game and PIE worlds only (not in the editor's level-editing world). * `Core/DescentHandle.h`: one handle type for every Register/Unregister pair. * Boot order constants beyond section 1.5: `BeforeAll`, `CreateUi` (450, between the stream and the character), `AfterAll`; and a real boot step `CoreSeams` (`Core/DescentCoreBoot.cpp`) that fails the boot, by name, if a core seam is missing from the world. * Late steps and sim steps accept `RateHz` (section 1.4 says "HUD model (10 Hz)", "dashboards (8 Hz)"): the callback is called at most that often, with the accumulated dt. * State sections `boot` (registered steps and what the last boot did), `env_query` (who provides dry space), `stream` (the points the world is asked to load around). * `Debug/DescentCommandUtil.h`: `ParseNumbers`, `ParseBool`, and `Fail` (logs `DESCENT_CMD_FAIL : ` and fails a running scenario, section 9.3). The existing commands now use it. * `FDescentScenarioContext::Sim()`, `Snapshot()` (the state dump as an object) and `LastShotStats` (the luminance numbers of the previous `S.Shot`), so a scenario can `S.Expect` on state and brightness. * `run_scenario.ps1 -Fps`, `-RealTime`; `import_assets.ps1 -Only`; the scenario runner now fails at start-up if a boot step failed. * Scenarios `core_sim` (the sim in a running game) and `selftest_expect` (**fails on purpose**, proves a failed `ExpectNear` names label and numbers). ## Guessed * The unit of `Look` (above). * That `Pause` should stop the tick function but not `Step()` itself, so FastForward and tests can always drive the sim. A paused game keeps running the late steps (the HUD and pause menu need them). * The 0.25 s clamp of the late-step dt (`Tune::Sim::MaxLateDt`). The design clamps only `Step`. * Positions given to the environment query are Unreal units (what `GetActorLocation()` returns); metre variants exist (`IsDryAtMetres`, `AmbientTemperatureAtMetres`). * Fill-light brightness of the showcase rig: raised about 1.23x to bring the pictures back to the brightness they had with Lumen on (mean luma 0.0664 -> 0.0715, centre 0.154 -> 0.151 at `front34`). ## Not run, or not proven * Pressing Play inside an editor window (PIE), `OpenEditor.bat`, and `PlayGame.bat` as a visible window were not run. The `-game` start that `PlayGame.bat` performs was run with `-RenderOffscreen` and no scenario: it booted on `Descent_Main` under `DescentGameMode` with the fly pawn, the boot report said `CoreSeams` ran and passed. * The sim's two tick functions run in real play (`core_sim` proves 1/30 s steps, `WaitSim`, pause and the intent override under the engine's tick), but their position relative to the camera manager (`LateTick` in `TG_PostUpdateWork` "after the camera manager has updated") and the character prerequisite cannot be shown until a character and a consumer exist. * The user's editor on the main project has the old module loaded: after the merge it must be closed and reopened, because `ProceduralMeshComponent` is now an enabled plugin (a plugin change needs an editor restart). * `ProceduralMeshComponent`, `PhysicsCore`, `Slate`, `SlateCore`, `UMG` are linked but not used by any code yet. * `S.WaitStreamIdle` was left for the terrain track, as asked. ## For the next tracks * Read STATUS.md section 9 ("Conventions for parallel work") before creating a file. * The showcase rig's own fog and exposure will double up with `ADescentEnvironment` once that exists (M1): call `ADescentShowcaseRig::SetOwnEnvironment(false)` from the scenarios, or let the environment light the shot. * With the map empty, any scenario that takes a picture must put something lit in the world first (the black-frame check fails it otherwise). `smoke` spawns the rig for that. * Several existing source files have CRLF line endings and others LF. Keep a file's own endings when you edit it, or the three-way merge sees every line as changed.