fix #28: port retail's sky default-script playback (aurora) and the particle facing law
The aurora was never missing data — it was a missing mechanism plus a misread. New decompile evidence closes the April-2026 contradiction: retail plays the sky carriers' PES through the Setup's own DefaultScript (GameSky::MakeObject @0x00506EE0 -> CPhysicsObj::makeObject @0x00513970 sets state|=0x80000; animate_static_object @0x00513DF0 ticks ScriptManager + ParticleManager). The pes_id column stays dead — that half of the April finding stands; the ids are byte-equal mirrors. - SkyPesFrameController is now the production owner (ACDREAM_ENABLE_SKY_PES deleted): script ids resolve from the Setup DefaultScript (SkyObjectData.DefaultScriptId; the pes_id column is a one-time-logged cross-check), slots persist by (index, gfx id, properties) per CreateDeletePhysicsObjects @0x005073C0 — a day-group swap keeping the carrier no longer restarts its emitters — and stale slots stop before replacements claim the slot-derived owner id. - RetailParticleFacing ports calc_draw_frame @0x0050DFA0: degrade mode 2 faces the viewer roll-free (set_vector_heading) instead of the camera plane; modes 3/4/5 spin the authored frame around one local axis (rotate_around_axis_to_vector) — Dereth authors 54 mode-5 emitters that previously got no facing at all; 1,583 mode-2 emitters get the exact law; authored/mode-1 paths are unchanged. - The 2026-08-23 'whole-sky tint' was the Rainy-group lightning/thunder PES playing at the debug anchor inside their 0.03-0.19 window, not the aurora: the aurora is nine faint viewer-facing glows pulsing on 6.7/15/55-minute rebirth cycles, in every day group, all day. Research: docs/research/2026-08-23-sky-default-script-port.md. Register: AD-112 filed (camera-anchored synthetic owners vs sky-cell physics objects). ISSUES #2 corrected (the playback ban is lifted by the new evidence); #28 fix landed pending the connected night gate. Tests: RetailParticleFacingTests (16), SkyPesFrameControllerTests (6); hermetic suites App 6,076/0, Core 4,905/0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6f47740af0
commit
18fce7bb5a
13 changed files with 906 additions and 113 deletions
|
|
@ -16095,7 +16095,7 @@ additional flash-shader work).
|
|||
|
||||
**Description:** Lightning/storm sky visuals still do not match retail. A 2026-04-28 named-retail recheck disproved the prior assumption that `SkyObject.PesObjectId` drives sky-render flash particles: `SkyDesc::GetSky` copies the field into `CelestialPosition.pes_id`, but `GameSky::CreateDeletePhysicsObjects`, `GameSky::MakeObject`, and `GameSky::UseTime` never read it.
|
||||
|
||||
**Root cause / status:** Open again. The sky-PES path is non-retail and must stay disabled for normal rendering. The remaining mismatch likely lives in the sky/weather mesh material path, the lightning/fog flash path, or another weather subsystem outside `GameSky`; do not reintroduce per-SkyObject PES playback without new decompile evidence.
|
||||
**Root cause / status:** CORRECTED 2026-08-23 — the "must stay disabled" ban is lifted by new decompile evidence: retail DOES play the sky carriers' PES, via the Setup `DefaultScript` → `CPhysicsObj::makeObject` default-script path (never via the `pes_id` column, which remains dead — that half of the April finding stands). Sky default-script playback is production as of the C.1.5c port (`SkyPesFrameController`, research `2026-08-23-sky-default-script-port.md`). The lightning-flash carriers (`0x02000BA6` → `0x33000453`, windows 0.03–0.19 / 0.40–0.50 / 0.91–0.98 on Rainy groups) now fire through it; whether the flash PRESENTATION matches retail (sky-wide crossfade vs a sprite) still needs its own storm-window gate.
|
||||
|
||||
**Files:**
|
||||
- `src/AcDream.App/Rendering/Sky/SkyRenderer.cs` — sky/weather mesh draw, material state, pre/post split
|
||||
|
|
@ -16142,11 +16142,26 @@ additional flash-shader work).
|
|||
|
||||
## #28 — Aurora ("northern lights") effect not rendered
|
||||
|
||||
**Status:** OPEN
|
||||
**Status:** FIX LANDED 2026-08-23 — awaiting the connected visual gate
|
||||
**Severity:** LOW (aesthetic feature-parity)
|
||||
**Filed:** 2026-04-26
|
||||
**Component:** sky / vfx
|
||||
|
||||
**2026-08-23 resolution (the C.1.5c mechanism, found):** the sky PES ids ride
|
||||
the carrier Setups' own `DefaultScript` (byte-equal to the dead `pes_id`
|
||||
column) and retail plays them through the ordinary default-script machinery —
|
||||
`GameSky::MakeObject @0x00506EE0` → `CPhysicsObj::makeObject @0x00513970`
|
||||
(`state |= 0x80000`) → `CPhysicsObj::animate_static_object @0x00513DF0`. The
|
||||
aurora carrier (`0x02000714` → PES `0x330007DB`) is present in ALL 20 day
|
||||
groups around the clock; visibility is purely "faint additive glows over a
|
||||
dark sky", pulsing on the emitters' 6.7/15/55-min rebirth cycles. The April
|
||||
"colored wash" experiment was run inside a Rainy day group's lightning window
|
||||
— the flash/thunder PES at the camera anchor, not the aurora, made the wash.
|
||||
`SkyPesFrameController` is now the production owner (no env flag), with
|
||||
retail's slot-identity persistence and the `calc_draw_frame @0x0050DFA0`
|
||||
facing law in the particle renderer. Full chain:
|
||||
`docs/research/2026-08-23-sky-default-script-port.md`; register AD-112.
|
||||
|
||||
**Description:** Retail renders a dynamic colored "light play" effect in the sky during certain Rainy/Cloudy DayGroup time windows. The user describes it as aurora-borealis-style. acdream renders no comparable effect.
|
||||
|
||||
**Root cause / status:** Open again. The prior root cause was wrong: `CelestialPosition.pes_id` exists in the retail header and is populated by `SkyDesc::GetSky`, but named retail `GameSky` code does not read it during sky object creation, update, or draw. A 2026-04-28 C.1 experiment that played those PES ids produced colored blobs/wash that did not match retail's broad aurora-like rays, and the path is now debug-only behind `ACDREAM_ENABLE_SKY_PES=1`.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
119
docs/research/2026-08-23-sky-default-script-port.md
Normal file
119
docs/research/2026-08-23-sky-default-script-port.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# Sky default-script (aurora/lightning/thunder) — the retail mechanism, proven
|
||||
|
||||
**Date:** 2026-08-23 · **Issues:** #28 (aurora), #2 (lightning, partial), #29 (clouds — not addressed here) · **Phase:** C.1.5c
|
||||
|
||||
## The April contradiction, resolved
|
||||
|
||||
Two prior research passes (`2026-04-23-sky-pes-wiring.md`, `2026-04-28-pes-pseudocode.md`)
|
||||
correctly proved `GameSky` never **reads** `CelestialPosition.pes_id`
|
||||
(`SkyDesc::GetSky @0x00501EC0` writes it at 0x00501FC9; no reader exists), and
|
||||
issue #2 therefore banned per-SkyObject PES playback "without new decompile
|
||||
evidence". This document is that evidence. Both were right and both missed the
|
||||
actual route:
|
||||
|
||||
**The sky PES ids ride the sky Setups' own `DefaultScript`, and retail plays
|
||||
them through the ordinary object default-script machinery — the `pes_id`
|
||||
column is a dead mirror of the same ids.**
|
||||
|
||||
Verified in the installed Dereth DAT: Setup `0x02000714` (aurora carrier,
|
||||
parts `0x010001EC`) has `DefaultScript = 0x330007DB` — byte-equal to its
|
||||
SkyObject's `PesObjectId`. Same holds for `0x02000589→0x3300042C` (thunder
|
||||
ping-pong), `0x02000588→0x33000428` (thunder variant), `0x02000BA6→0x33000453`
|
||||
(lightning flash).
|
||||
|
||||
## The retail chain (named decomp, every link read this session)
|
||||
|
||||
1. `GameSky::UseTime @0x005075B0` (30 Hz) → `CRegionDesc::GetSky` →
|
||||
`SkyDesc::GetSky @0x00501EC0` rebuilds the `CelestialPosition` list.
|
||||
Per-object visibility: **if `begin_time == end_time` the object is always
|
||||
included**; otherwise `begin <= t <= end` gates the gfx id (out-of-window →
|
||||
`INVALID_DID`). The aurora object has `begin=end=0.00` in **all 20 day
|
||||
groups** → always present, all day.
|
||||
2. `GameSky::CreateDeletePhysicsObjects @0x005073C0`: an existing sky object
|
||||
is **kept** when its current DataID equals the wanted gfx id AND the
|
||||
properties word is unchanged AND (`props & 4` → `LScape::weather_enabled`
|
||||
did not flip). Only a mismatch destroys/recreates. ⇒ the aurora object —
|
||||
same id in every group — **persists across day-group changes**, and its
|
||||
emitters keep their particle population.
|
||||
3. `GameSky::MakeObject @0x00506EE0`: `props & 4` objects are only created
|
||||
when `LScape::weather_enabled != 0`; `props & 1` selects `after_sky_cell`
|
||||
(post-scene) vs `before_sky_cell`. Creation is
|
||||
`CPhysicsObj::makeObject(gfx_id, 0, 0)`.
|
||||
4. `CPhysicsObj::makeObject @0x00513970` → `InitPartArrayObject`: a Setup
|
||||
with `default_script_id != 0` sets `state |= 0x80000` and registers via
|
||||
`CPhysics::AddStaticAnimatingObject @0x00509AF0`.
|
||||
5. `CPhysicsObj::animate_static_object @0x00513DF0` (per tick): state 0x80000
|
||||
→ `ScriptManager::UpdateScripts` (starts/advances the default script — the
|
||||
PES) and updates the object's `ParticleManager`. This is the ~150/min
|
||||
`CallPES` churn the 2026-04-30 live trace counted (the thunder PES
|
||||
`0x3300042C` ping-pongs via `CallPES` chains).
|
||||
|
||||
## The particle laws confirmed against our port
|
||||
|
||||
- `ParticleEmitterInfo::GetRandomOffset @0x005174A0`: random vector, **minus
|
||||
its projection onto `offset_dir`**, normalized, × rand[min,max] — a disk
|
||||
PERPENDICULAR to the dir (a shell when dir is zero). Our
|
||||
`ParticleSystem.RandomOffset` is byte-faithful. The aurora's 450–700 m
|
||||
"Z-dir" offsets are therefore a horizontal RING around the sky-object
|
||||
origin, not a column above it.
|
||||
- `Particle::Update @0x0051C290` writes **only the part origin** per type
|
||||
formula (our `ComputePosition` matches, incl. Swarm cos/sin); only the
|
||||
GR/LR parabolic variants rotate.
|
||||
- `ParticleEmitter::SetInfo @0x0051CE90`: parts are ordinary
|
||||
`CPhysicsPart::makePhysicsPart(hw_gfxobj_id)`; there is no special "2D
|
||||
particle" draw. `CPhysicsPart::Draw @0x0050D7A0` always feeds
|
||||
`DrawMesh(gfxobj[deg_level], &draw_pos)`.
|
||||
- **The facing law** — `CPhysicsPart::calc_draw_frame @0x0050DFA0`, driven by
|
||||
the FIRST degrade entry's mode (`GfxObjDegradeInfo::get_degrade
|
||||
@0x0051E4B0`; `viewer_heading` = normalized part→viewer from
|
||||
`UpdateViewerDistance @0x0050E030`):
|
||||
|
||||
```
|
||||
draw = pos
|
||||
switch deg_mode:
|
||||
2: Frame::set_vector_heading(draw, viewer_heading) // face viewer, roll-free
|
||||
3/4/5: Frame::rotate_around_axis_to_vector(draw, X/Y/Z, vh) // cylindrical, one free axis
|
||||
else: authored orientation (mode 1, mode 0, out of range)
|
||||
```
|
||||
|
||||
Our renderer camera-plane-aligned every "billboard" particle
|
||||
(`cameraRight`/`cameraUp`); retail faces each part toward the viewer
|
||||
per-part and honors constrained modes. `CPhysicsPart::Always2D @0x0050D8A0`
|
||||
(mode != 1) is only consulted for **cell membership**
|
||||
(`CLandCell::add_all_outside_cells @0x00533360`), not drawing.
|
||||
|
||||
- The aurora emitters (`0x32000455/56/57`): BirthratePerSec 10, max 3,
|
||||
initial 3, lifespans 3300/900/400 s, StartTrans 0.8 → FinalTrans 1.0
|
||||
(≤20 % opacity fading to nothing), StartScale 7–8, sprites
|
||||
`0x01001A61..63` = single ±137.5 m quads whose 64×64 additive textures are
|
||||
soft glow blobs (row/col profiled — no banding; peak RGB 36–71/255). First
|
||||
degrade mode = **2** on all three. The visible aurora is therefore nine
|
||||
huge, faint, viewer-facing glows in a slow Swarm drift — a pulse that
|
||||
re-brightens when a cohort is reborn (~6.7/15/55 min cycles), not a steady
|
||||
fixture.
|
||||
|
||||
## Why the 2026-08-23 experiment looked like "whole-sky tint"
|
||||
|
||||
The debug controller (`ACDREAM_ENABLE_SKY_PES=1`) ran under day group 16
|
||||
(Rainy) at t=0.125 — inside the lightning window (0.03–0.19) — so the
|
||||
**lightning-flash and thunder PES** played at the camera anchor alongside the
|
||||
aurora. A flash sprite at the anchor IS a full-screen additive wash. The
|
||||
aurora itself was drowned under a faithful-but-wrong-conditions storm.
|
||||
|
||||
## Port deltas (this change)
|
||||
|
||||
1. Sky default-script playback becomes **production** (no env flag): every
|
||||
visible sky object whose Setup carries a `DefaultScript` plays it through
|
||||
`PhysicsScriptRunner`, anchored at the camera (retail sky-cell space is
|
||||
viewer-centered), pass-routed by `props & 1`.
|
||||
2. **Persistence contract**: script/emitter state is keyed by
|
||||
(gfx id, properties) per `CreateDeletePhysicsObjects` — a day-group flip
|
||||
that keeps the same carrier Setup must NOT restart its emitters.
|
||||
3. Weather gating: `props & 4` objects follow the weather-enabled state
|
||||
(acdream's weather system), matching `MakeObject`'s guard.
|
||||
4. `calc_draw_frame` facing law in the particle renderer: per-sprite degrade
|
||||
mode picks face-viewer (2), axis-constrained (3/4/5), or authored (else)
|
||||
orientation — replacing the blanket camera-plane alignment.
|
||||
|
||||
Script ids resolve from the **Setup's DefaultScript** (the retail source);
|
||||
the `PesObjectId` column is only a cross-check.
|
||||
Loading…
Add table
Add a link
Reference in a new issue