Files the independent review corpus (fable/opus/external + audit, DAT-format, F418 DAT-geometry, retail decomp reconstruction) and the synthesis that adjudicates their disagreements: retail roots INTERIOR at the posed terrace defect pose with a ONE-CELL flood and ov=1 (the free captures rooted outdoor - both were real); the falls are outdoor landblock emitters 0xCF418000-13; the "thin seam bands" claim is DAT-refuted (full-size exits; the seam is a coincident double exit-to-outside plane at y=48); clear+seals live inside retail''s ov>0 block with a one-frame seal latch. Carries the instrument-first plan (falls-owner trace, depth checkpoints, pose conformance) and the decomp-pinned repair sequence toward FW4''s single-owner goal. Also sweeps in the probe scaffolding slice 5''s path-limited add had missed (RenderingDiagnostics field + the launch-options row wording). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
93 lines
4.6 KiB
Markdown
93 lines
4.6 KiB
Markdown
# Cathedral review — DAT-format facts (companion report)
|
||
|
||
Delivered 2026-08-30 by the DAT-format verification agent (decompiled the
|
||
actual `Chorizite.DatReaderWriter 2.1.7` NuGet binary with ilspycmd and
|
||
cross-checked against `docs/research/named-retail/acclient.h`). Key facts
|
||
for the cathedral synthesis; flagged caveats preserved.
|
||
|
||
## Sourcing caveats
|
||
|
||
- Our DAT parser is the CONSUMED NuGet `Chorizite.DatReaderWriter 2.1.7`
|
||
(no vendored source; facts below come from decompiling the exact linked
|
||
DLL).
|
||
- `references/WorldBuilder` is an uninitialized submodule in THIS worktree
|
||
(read from the main worktree at a different SHA — flagged).
|
||
- `references/ACViewer` does not exist in either worktree (claims about
|
||
ACViewer: UNVERIFIED).
|
||
|
||
## EnvCell record (read order, decompiled Unpack)
|
||
|
||
Flags (int) → self-Id (uint, duplicate) → NumSurfaces (byte) → NumPortals
|
||
(byte) → NumVisibleCells (ushort) → Surfaces[](ushort) → EnvironmentId
|
||
(ushort) → CellStructure (ushort) → Position (Frame) → CellPortals[] →
|
||
VisibleCells[] (ushort) → [HasStaticObjs 0x2] StaticObjects (count +
|
||
Stab{Id,Frame}[]) → [HasRestrictionObj 0x8] RestrictionObj.
|
||
|
||
`EnvCellFlags`: SeenOutside=0x1, HasStaticObjs=0x2, HasRestrictionObj=0x8.
|
||
**0x4 is unclaimed.**
|
||
|
||
Retail cross-check: `CEnvCell : CObjCell` (acclient.h:32072-32091) maps
|
||
1:1; retail's `stab_list` lives on the BASE `CObjCell`
|
||
(acclient.h:30914-30932) and is the **PVS list of CELL IDS** — NOT placed
|
||
objects. The DatReaderWriter `Stab{Id,Frame}` placed-object struct is a
|
||
coincidental homonym (zero matches for `Stab` in the named-retail header).
|
||
|
||
## CellPortal / BuildingPortal
|
||
|
||
`CellPortal { PortalFlags Flags; ushort PolygonId; ushort OtherCellId;
|
||
ushort OtherPortalId; }` — `PortalFlags: ExactMatch=1, PortalSide=2`.
|
||
**No 0x4 member anywhere** (package, our code, WorldBuilder, and retail's
|
||
own `CCellPortal` decode exactly two semantic fields: portal_side,
|
||
exact_match). NOTE: this contradicts the earlier campaign note
|
||
"CCellPortal DAT flag 0x4 = leads outside" — the outside link is the
|
||
`OtherCellId == 0xFFFF` sentinel, not a flag bit.
|
||
|
||
- ExactMatch consumers: `PortalVisibilityBuilder.cs:1168-1183` (skips
|
||
reciprocal clip — decomp:433689), Walk factories
|
||
(`WalkBuildingFactory.cs:76`, `WalkCellFactory.cs:94`).
|
||
- PortalSide convention: `(Flags & 0x2) == 0 → normal points INTO the
|
||
owning cell` (`CellPortal.cs:23-24`, `PortalInfo.cs:22-44`);
|
||
`WalkCellFactory.cs:93`: `PortalSide = (Flags & 0x2) != 0 ? 0 : 1`.
|
||
- `OtherCellId == 0xFFFF` = the outdoor-exit sentinel (18+ consumers);
|
||
the walk world remaps it to `0xFFFFFFFFu`.
|
||
|
||
`BuildingPortal` (BuildingInfo.Portals) is a DISTINCT dat type — carries
|
||
its own **packed StabList of cell ids** (retail `CBldPortal` with
|
||
num_stabs/stab_list + `sidedness`). The walk's `WalkBuildingFactory.cs:81`
|
||
reads it directly; the older `Wb.BuildingLoader` path DISCARDS it and
|
||
recomputes by BFS.
|
||
|
||
## LandBlockInfo
|
||
|
||
`NumCells → Objects[Stab] → Buildings[BuildingInfo{ModelId, Frame,
|
||
NumLeaves, Portals[BuildingPortal]}] → [flag] RestrictionTable`.
|
||
Confirmed field-for-field; consumer `LandblockLoader.cs:69-103`.
|
||
|
||
## Water / waterfall (part d)
|
||
|
||
- `LandDefs::WaterType` is COMPUTED client-side from terrain paint (types
|
||
0x10-0x14 WaterRunning..WaterDeepSea); AcDream already computes it for
|
||
physics (`TerrainSurface.cs:92-128`). It is NOT packed in the records.
|
||
- `SurfaceTexture.Textures` is a multi-frame list (the structural shape of
|
||
a flip-book animation) but EVERY consumer in both repos freezes one
|
||
fixed index (`Textures[0]`, WB `[^1]`) — **no water/texture animation is
|
||
implemented anywhere**; whether retail animates via this list is
|
||
UNVERIFIED.
|
||
- Which object IS "the waterfall" near the cathedral: UNVERIFIED from
|
||
source — two old bug comments treat it as OUTDOOR landscape-alpha
|
||
content (`PortalVisibilityBuilder.cs:730-736`,
|
||
`RetailPViewRenderer.cs:714-726`), consistent with a translucent stab —
|
||
but note the live probes identified the terrace falls PARTICLE owners as
|
||
EnvCell StaticObjects of cell 0xF4180106 (ids 4f418012-15), which is
|
||
the `HasStaticObjs` list above; both can be true (mesh stab outdoors +
|
||
emitter stabs in cells).
|
||
|
||
## Notable corrections this report makes to campaign lore
|
||
|
||
1. "DAT flag 0x4 = leads outside" (PV campaign memory) — REFUTED: no 0x4
|
||
exists; outside = OtherCellId 0xFFFF.
|
||
2. "stab list" ambiguity — retail stab_list = PVS cell ids on CObjCell;
|
||
placed objects are a different structure; docs/comments conflating the
|
||
two should be read carefully.
|
||
3. Building portals carry authored per-portal cell StabLists in the dat —
|
||
the old Wb path recomputes what the dat already provides.
|