Commit graph

4287 commits

Author SHA1 Message Date
Erik
7adbffcb6a docs(render): record owner-supplied self-gate poses
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 22:05:51 +02:00
Erik
5a2792d689 feat(physics): S2 chunk 1b - callers supply the visual part array; installed-DAT comparator
Every production registration now hands ShadowObjectRegistry the object's
whole visual part array beside its collision dispatch: static publication
(App LandblockPhysicsPublisher and the headless Content twin) through
ShadowShapeBuilder.FromStaticRenderParts, live entities (Runtime
LiveEntityCollisionBuilder) through the new FromSetupRenderParts, which walks
every Setup part with the same physics-sphere-else-drawing-sphere and
part-box rule from the PhysicsDataCache Runtime already reaches. Nothing
consumes the retail products yet; the App hermetic lane still passes
6,758/6,758.

The Lane=InstalledDat comparator registers five real fixtures through the
real publication inputs and prints retail CELLARRAY, collision cells, and
the old render cells side by side: Facility Hub stair Setup 0x02000623
(7 cells incl. 0x8A02015F/015E), cathedral ramp 0x020009A2 (3 cells, the
genuine multi-part case), the #334 Neftet formation (25 cells), and a
landblock-edge crosser (6 cells, 2 in the neighbor block). All three
answers agree for BSP-bearing objects, as the shared primitive predicts;
the divergence chunk 3 expects appears only for decorative non-BSP parts.

Core Physics 2,202/2,202; Runtime 1,884/1,884; App hermetic 6,758/6,758;
comparator + stair pin 5/5; solution Release build 0 warnings / 0 errors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 21:52:35 +02:00
Erik
059b8883ab feat(physics): S2 chunk 1a - retail cell array and per-part entries beside the collision flood
Campaign OVERHAUL S2 chunk 1 (Core half). ShadowObjectRegistry accepts the
object's whole visual part array as an optional registration input and
computes retail's CELLARRAY from it as a retained side product:

- route per CPhysicsObj::calc_cross_cells_static @0x00515160: cylsphere
  (CObjCell::find_cell_list @0x0052b9f0 over the Setup's authored
  cylspheres, carried as the Cylinder shapes of the COLLISION dispatch) when
  (state & 0x10000) == 0 and a cylsphere exists, else the bbox route
  (find_bbox_cell_list @0x00510fc0 via CellTransit.BuildShadowCellSetFromParts
  over every visual part: physics sphere else drawing sphere, part box);
- per-cell part entries in array-then-part order for every part
  (CPartArray::AddPartsShadow @0x00517e40), clip planes required iff the
  array has more than one cell;
- Deregister clears everything (remove_shadows_from_cells @0x00511230);
  UpdatePosition/CommitSetPosition recompute; ReplaceMultiPartPayload swaps
  the part array without re-flooding.

_entityToCells and _cells are untouched; no production caller passes the
part array yet (chunk 1b), so this is a zero-behavior change. The lead
corrected the implementer's route decision, which had inspected the visual
part array for cylinders; retail's GetNumCylsphere reads Setup collision
data. Core Physics 2,202/2,202.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 21:20:40 +02:00
Erik
015b660d0f test(render): pin cell-shell batch-to-index-segment pairing under reorder
Uploads a cell-shell mesh whose storage order is the reverse of its surface
order and asserts each uploaded batch's FirstIndex reads back its own
indices from the arena. Guards the G1 regression fixed at 8c6563ca.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 21:10:16 +02:00
Erik
e7ad25a705 docs(render): S2 plan packet - membership ownership map and revised chunks
Read-only trace of every production owner of cell membership (render and
physics), the retail transaction they must collapse into (Contracts A/B),
and the five S2 chunks re-cut on that evidence: the two static floods are
one CellTransit walk with different part inputs; retail uses the whole
part array once and registers every part in every array cell; children
inherit at registration; topology consolidation moves to S3.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 20:57:04 +02:00
Erik
75873886f3 docs(render): close S1 at G1 PASS; open S2
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 20:43:51 +02:00
Erik
8c6563cada fix(render): pair cell-shell index segments with their reordered batches
The S1 review round ordered cell-shell batches by source surface index in
ObjectMeshManager.UploadGfxObjMeshData but left the index segments handed
to the arena in TextureBatches dictionary order. FirstIndex is positional
over the segments, so every cell shell's batch pointed at another batch's
index range: magenta placeholder walls, stretched textures, and missing
faces in every dungeon and house (G1 FAIL 2026-09-02). One upload order is
now computed once and used by the count, fill, and batch loops alike.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 20:31:59 +02:00
Erik
e2543d0ef0 fix(content): S1 review round - retail default sides shape, mask hoist, upload order
Campaign OVERHAUL S1 review fixes (two Opus lens reviews, findings verified
by the lead against the decomp):

- a raw sides_type outside 0/1/2 constructs retail's default single-side
  shape (ConstructMesh @0x0059DFA0 loop bounds default to 1) instead of
  dropping the polygon; still counted as a data anomaly (corpus has none);
- the positive-surface stippling mask OR runs once per polygon before the
  degenerate-fan guard, as retail's count loop does (pseudo-C 426859-426866);
- untextured slots keep their mask accounting but bake no texture and no
  vertices (contract §9 item 3); the dev pak shrinks by 114 KB;
- failed surface-override / Surface / texture-dependency lookups are
  attempted and logged once per slot, not once per candidate;
- cell-shell batches upload in ascending source surface index, retail's
  built-EnvCell subset draw order (ConstructMesh attribute-range scan,
  DrawMesh @0x0059D4A0); ordinary GfxObj meshes keep storage order;
- CellMesh.HasDrawableGeometry documented as the admission rule without
  texture-dependency resolution (a conservative superset of emission);
- the stippling/surface equivalence sweep's cell half is pinned at zero
  again; InAscendingSurfaceOrder is marked bake/upload/test-only;
- plan §5: reviewer findings are verified by the lead, one skeptic at most
  for a blocking finding, never more than five agents per step.

Three new Content tests pin the mask hoist, the vertex-free untextured
slot, and the single-side fallback. Content 213/213, Core Meshing and
Conformance green, App hermetic 6,757/6,757, Release build 0/0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 19:37:25 +02:00
Erik
0840d5fb77 docs(render): document the checkpoint's probe flags and re-pin portal_depth
The b3b7d922 investigation checkpoint committed two probe read sites
(ACDREAM_PROBE_CATHEDRAL_SKIP_PUNCH, ACDREAM_PROBE_FACILITY_STAIRS) without
their launch-options rows, and removed the #117/#129 bias from
portal_depth.vert without re-pinning its SPIR-V oracle hash. Both left the
hermetic App lane red at the OVERHAUL v2 base. Rows added (both default-off,
scheduled for deletion in S5); the shader pin now records the binary on the
branch, with S4 named as the owner of its acceptance.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 19:14:57 +02:00
Erik
b681717c30 feat(core): S1 one CellStruct interpretation, installed-DAT scan, retire AP-234
Campaign OVERHAUL S1 chunk B.

- CellMesh.Build's render role is deleted; CellMesh.HasDrawableGeometry
  is the exact predicate (any sides_type candidate whose resolved surface
  passes the built-EnvCell (Surface.Type & 6) != 0 test), and the
  streaming build job consumes it. Core and Content no longer carry two
  CellStruct interpretations.
- Installed-DAT scan over the complete Environment corpus (5,346
  landblocks, 729,888 cells, 8,601,560 polygons, 8,608,746 candidates):
  3,197 old-rule admissions were untextured surfaces the NoPos proxy let
  through; zero new-only; zero unexplained; zero unknown sides values;
  counts pinned as goldens against the contract's DAT hashes.
- Canonical pins: 0xF4180104 has eight ST_DOUBLE clip-map polygons and 44
  drawable side calls; the canonical NoPos surfaces are type 0x11 and are
  constructed but skipped; two independent extractions of all ten
  canonical cells hash identically.
- AP-234 retired from the divergence register (161 active rows) with
  ConstructMesh 0x0059DFA0 / DrawEnvCell 0x0059F170 / DrawMesh 0x0059D4A0.
- StipplingSurfaceEquivalenceTests no longer claims a build-time NoPos
  skip; the cell half is report-only, the building half stays pinned.
- Inventory and policy remarks updated; plan ledger records chunk A and
  the capture kit.

Core Meshing+Conformance 95/95, Content 208/208 (Lane!=Timing,
Lane!=PreparedPackage), App EnvCell/LandblockBuild/Streaming 432/432,
Release solution build 0 warnings / 0 errors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 19:11:17 +02:00
Erik
acf172469e feat(content): S1 exact CellStruct surface-index construction, recipe 8
Campaign OVERHAUL S1 chunk A. Retail's D3DPolyRender::ConstructMesh
@0x0059DFA0 is ported as one pure Core descriptor plus the Content
extraction that consumes it:

- side candidates come only from sides_type (0/1/2); NoPos/NoNeg mean
  UV-array absence only and never suppress a side (CPolygon::UnPack
  @0x00538650);
- ST_DOUBLE's second copy is reversed with a negative normal; ST_BOTH's
  negative side has a negative normal and forward fan order (reverse is on
  the copy ordinal, not the side ordinal);
- an absent UV-index array is UV index 0 (ConstructMesh @0x0059E691
  xor ebx,ebx, arbitrated on the PDB-paired binary); copyVert @0x0059C080
  zeroes coordinates only for a negative or out-of-range index or a vertex
  without UVs, never by clamping to slot 0;
- the subset owner is the source surface-array index, emitted in ascending
  slot order with retail's per-slot mask (2 > 8 > 4 precedence, positive
  surface OR on signed stippling > 0);
- built-EnvCell admission is (Surface.Type & (BASE1_IMAGE|BASE1_CLIPMAP))
  != 0 after surface resolution (DrawEnvCell @0x0059F170 -> DrawMesh
  @0x0059D4A0 arg4=1); untextured slots are constructed but not emitted;
- cell batches carry SourceSurfaceIndex, RetailSurfaceMask, RawSurfaceType,
  IsCellShell, and fixed clockwise raster cull (RenderMeshSubset
  @0x0059CA10); authored sides_type is no longer stored as GPU cull.

Prepared-mesh serializer gains the four fields; bake recipe 7 -> 8 with a
FullRebuild migration; pak format stays 2 (pinned). Ordinary GfxObj
extraction is unchanged. AP-234's register row and CellMesh unification
land in chunk B.

Core: 32 descriptor tests. Content: 170/170. Bake: 18/18. Launcher.Core:
365/365 (Lane!=Linux). Solution Release build 0 warnings / 0 errors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 18:40:33 +02:00
Erik
14d8fe6478 tools(render): fix printf newline escapes in the OH alpha-depth template
The AM and PM breakpoint actions carried a single-backslash newline; cdb
needs the doubled form inside a quoted bp action, as the other lines use.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 18:19:35 +02:00
Erik
ebaa41df1a tools(render): OH retail capture scripts for the S3/S4 answer key
Recon script, three capture templates (walk / parts / alpha-depth),
runner, and operator README under tools/walk-oracle/oh/. FW0 line formats
are kept byte-identical; new EC/OC/PD/DM/AM/FL/PM/PC line kinds are
documented. Auto-detach uses the fall-through + top-level qd recipe; qd
never appears inside a breakpoint action. Lead-resolved: DBObj::m_DID is
+0x28 (header layout, first base of CGfxObj and CObjCell, matches the
proven FW0 cell reads); the three D3DPolyRender alpha functions are static
cdecl with stack arguments, uint8 arguments read with by().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 18:09:11 +02:00
Erik
13fc7d8349 docs(render): rescope Campaign OVERHAUL to five production slices
v2 replaces the twelve-stage plan. OH1's evidence-grammar stage is parked
on quarantine/oh1-evidence-grammar-2026-09-02; the committed research
contracts stay binding. Stage mapping: OH2 -> S1, OH3 -> S2, OH4+OH5 -> S3,
OH6+OH7 -> S4, OH8-OH11 -> S5. Adds the working model (lead in the loop,
bounded chunks, time-box), the single retail capture session before S3,
and per-slice minimal evidence products. Carries the InitCell inflag
prose correction in the flood appendix and marks the T3 handoff superseded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:50:25 +02:00
Erik
5d907ae9ad docs(render): define OH1 retail world contract 2026-09-01 19:33:15 +02:00
Erik
5cd4fd2c71 docs(render): define OH2 CellStruct contract 2026-09-01 19:11:32 +02:00
Erik
eaea877662 docs(render): clean OH0 baseline formatting 2026-09-01 18:06:21 +02:00
Erik
fba07e7712 docs(render): establish Campaign OVERHAUL baseline 2026-09-01 18:05:40 +02:00
Erik
b3b7d922f1 checkpoint(render): preserve pre-overhaul investigation state 2026-09-01 18:04:24 +02:00
Erik
e880860291 fix(render): restore landscape objects and walk alpha order 2026-08-31 10:49:33 +02:00
Erik
4683ac6f72 docs(render): record Campaign FW closeout gates 2026-08-31 09:21:19 +02:00
Erik
4808d4d10b refactor(render): remove Campaign FW probes 2026-08-31 09:14:47 +02:00
Erik
b8befded8b checkpoint: preserve user-gated FW closeout fixes 2026-08-31 08:27:37 +02:00
Erik
a2f2eb7d78 refactor(render): remove stale portal products from frame exchange 2026-08-31 06:28:26 +02:00
Erik
4d0379744b fix(camera): complete retail in-head adjustment behavior 2026-08-31 06:18:37 +02:00
Erik
11e68aad82 fix(render): clip walk content to authored portal views 2026-08-31 06:15:12 +02:00
Erik
90eba0ec3c fix(camera): port retail offset adjustment laws 2026-08-31 05:42:23 +02:00
Erik
cb22691beb refactor(render): remove the production portal frame carrier 2026-08-31 05:34:46 +02:00
Erik
69e69408e8 refactor(render): delete legacy pview execution machinery 2026-08-31 05:27:25 +02:00
Erik
1be4889c1c refactor(render): require the production frame walk 2026-08-31 05:09:51 +02:00
Erik
cd08cd2ae8 fix(render): clip weather particles to walk views 2026-08-31 05:01:00 +02:00
Erik
837a33baff refactor(render): cull terrain by walk in-view cells 2026-08-31 04:54:03 +02:00
Erik
98d2d43fdc refactor(render): make the walk sole production visibility owner 2026-08-31 04:50:08 +02:00
Erik
2a3ec09a98 refactor(render): delete the dead cell visibility bfs 2026-08-31 04:46:20 +02:00
Erik
73ba1d3c32 refactor(render): delete the packed dispatcher 2026-08-31 04:44:22 +02:00
Erik
8d8aa715ee refactor(render): delete the packed pview product 2026-08-31 04:37:54 +02:00
Erik
78547718c7 fix(render): apply retail marker admission to the walk 2026-08-31 04:31:22 +02:00
Erik
a40a57b9b3 refactor(render): flush alpha at retail walk barriers 2026-08-31 04:25:34 +02:00
Erik
877e935ac4 refactor(render): publish the walk visible-cell set 2026-08-31 04:15:55 +02:00
Erik
c9fb7e7d4c refactor(render): detach packed pview product from production 2026-08-31 04:10:10 +02:00
Erik
ef12170a3c refactor(render): retire packed dynamic walk passes 2026-08-31 04:05:17 +02:00
Erik
2127c955f6 refactor(render): move outdoor dynamics onto landscape turns 2026-08-31 03:57:45 +02:00
Erik
474b05e7dc refactor(render): move root-cell dynamics onto walk turns 2026-08-31 03:44:32 +02:00
Erik
f9a80fbc44 refactor(render): move look-in dynamics onto walk turns 2026-08-31 03:39:03 +02:00
Erik
966836895f fix(render): draw look-in dynamics only at retail walk turns 2026-08-31 03:22:01 +02:00
Erik
572de1ec30 checkpoint: preserve cathedral look-in investigation state 2026-08-30 23:29:28 +02:00
Erik
c287db8651 docs: full session handover - cathedral state, open through-wall defect
Owner-requested handover for a successor session: worktree/branch/HEAD,
tonight''s ledger (falls + rain + torch fixes user-verified; slices 4+5
reverted; the seven-report corpus), the OPEN through-wall remote-player
defect with both attempted fixes and the post-fix [dyn-route] evidence
(the DynamicLast root-flood gate works; the remaining draw path is the
legacy look-in machinery), the leading punch-depth hypothesis marked
unverified, the retail-shaped fix direction, the remaining queue, all
probe families, and the binding lessons.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 22:17:30 +02:00
Erik
fc2e6b79bc fix(render): DynamicLast admits only the walk''s own root flood
The [dyn-route] trace pinned the through-wall remote player (visible
from 0xF4180101 AND outdoors while parented at 0xF4180112 - a cell
with no retail sightline chain from either): the legacy visibility
builder invents cross-building cell views at the cathedral (REAL
3-5-plane cones for 0x112, not the zero-plane trapdoor), the viewcone
admits his sphere, and he rides the last dynamics pass - post-clear on
interior roots (walls'' depth wiped) and post-world outdoors.

The stage-set split (synthesis plan step 4): an interior-parented
dynamic may ride DynamicLast ONLY when its parent cell is in THE
WALK''S OWN ROOT FLOOD (oracle-trace-conformant; retail draws look-in
occupants inside the landscape stage through the composed portal
chain, and unreachable cells'' occupants not at all). The frame
product''s build input gains RootFloodCells (the driver''s
InteriorFloodCells as a per-frame set); non-walk/diagnostic frames and
the comparison wrapper keep the legacy drawableCells meaning. The
[dyn-route] probe logs the new rootflood-excluded state.

Hermetic 6,762/0; InstalledDat walk conformance 40/1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 22:13:48 +02:00
Erik
4686a1ac74 probe(render): [dyn-route] DynamicLast admission trace + rain PASS note
The owner''s through-wall remote-player report (standing in 0xF4180101,
a player parented at 0xF4180112 - the south hall, geometrically
unseeable through the cathedral - renders through opaque walls; from
0xF4180104 he is correctly hidden). The DynamicLast admission chain
has three gates (indoor / old-apparatus look-in exclusion /
SphereVisibleInCell against old-assembly cell planes), and gate 3
carries a known trapdoor: a zero-plane scissor-fallback slice is
PASS-ALL. This trace logs, per entity ON CHANGE: parent cell, look-in
exclusion hits, the viewcone verdict, and the cell''s lifted-plane
shape, so one 0104<->0101 crossing with the remote player in place
pins the admitting gate. Rain gate 75eab42f is owner-PASSED.

Hermetic 6,762/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 21:55:24 +02:00
Erik
75eab42f3c fix(render): rain draws only while the player stands outside
The owner''s seam report (rain in the 0xF4180104/0xF4180101 crossing
strip where retail has none) led straight to retail''s actual rain
confinement, which is neither depth nor view clipping:
GameSky::Draw @0x00506ff0 gates its WEATHER pass (arg2==1) on
SmartBox::is_player_outside @0x00451e80 - Ghidra-arbitrated (BN''s
body was flag-idiom mush): (player objcell_id & 0xFFFF) < 0x100. The
sky pass always draws; rain draws ONLY while the PLAYER is in an
outdoor cell. One boolean - rain on the ledges, none the instant the
player crosses into an interior cell. Retail also runs the sky/weather
draw at DEPTHTEST_ALWAYS write-off (pc 0x00507063), confirming our
depth-disabled weather port; the missing piece was only this gate,
now applied at the executor''s weather site from the frame''s
PlayerCellId.

Hermetic 6,762/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 21:39:28 +02:00