Commit graph

6 commits

Author SHA1 Message Date
Erik
5dc4140c11 feat(render): Phase A8 — indoor visibility + streaming fixes batch
Lands the working A8 indoor-rendering and streaming fixes accumulated this
session. User has verified these visually to some degree (e.g. lifestone /
translucent meshes confirmed fine under the FrontFace flip; bridge / wall /
collision regressions confirmed fixed after travel); not every path has been
exhaustively gated. The cellar-flap defect remains OPEN and will be solved
the retail-faithful way via a dedicated brainstorm (see handoff docs).

Rendering core (reviewed, high confidence):
- EnvCellRenderer SSBO stride fix: upload packed Matrix4x4[] (64B) instead of
  the 80B CPU InstanceData struct the shader never expected — fixes the
  transform/texture "explosion" for any draw with >1 instance (cells that
  dedupe to a shared cellGeomId). Real root cause.
- WB-style global FrontFace(CW) + per-batch CullMode carried through the MDI
  layout (GroupKey + BuildIndirectArrays + DrawIndirectRange split into
  same-cull runs with absolute uDrawIDOffset per run).
- EntitySet partitioning (IndoorPass / OutdoorScenery / LiveDynamic) +
  WorldEntity.BuildingShellAnchorCellId so building shells scope to their
  dat-derived building cell instead of rendering everywhere.
- RenderOutsideInAcdream (look into buildings from outside) +
  CollectVisiblePortalBuildings frustum cull of portal bounds.
- Sky-when-inside-building + per-cell audit probe + GL-state probe.

Streaming / perf (test-covered; not independently code-reviewed this session):
- Near/far priority queues so near work wins over far; PromoteToNear carries
  full landblock + mesh data; LandblockEntriesWithoutAnimatedIndex avoids
  rebuilding the animated-lookup dict in the hot draw path. Fixes the
  bridge-not-appearing / missing-walls / broken-collision-after-travel
  regressions and improves post-transition FPS.

Tooling + docs:
- tools/A8CellAudit: offline dat cell/portal/building dumper (portals +
  buildings modes) — reproduces the cellar-flap investigation with no launch.
- docs/research cellar-flap root-cause + option-2 handoff (the didInsideStencil
  double-duty finding + the WB-recursive design decision + brainstorm prompt),
  entity-taxonomy, replan, issue-78 visibility investigation.

Diagnostics retained on purpose: ACDREAM_A8_DIAG_* gates, portal_stencil.vert
provisional pos.w clamp, and the probe families are kept (env-var gated, zero
cost when off) because the pending option-2 cellar-flap brainstorm needs them.
Strip in the option-2 ship commit.

Indoor branch stays behind ACDREAM_A8_INDOOR_BRANCH=1 (default off = pre-A8
visual). Build green; App tests + Core (streaming/dispatcher/loader) tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 10:14:50 +02:00
Erik
ed72704f7b feat(world): Phase A8 R1 — tag WorldEntity.IsBuildingShell at LandblockLoader
Adds a bool flag at the WorldEntity data layer set by LandblockLoader from
the source dat array: LandBlockInfo.Buildings → true (cottage walls, inn
walls, smithy walls); LandBlockInfo.Objects → false (trees, lampposts,
rocks, hitching posts).

Retail anchor: CLandBlock::init_buildings reads a separate BuildInfo**
array from objects (acclient.h:31893 num_buildings / buildings field;
acclient_2013_pseudo_c.txt:313854 init_buildings entry). WorldBuilder
preserves the same distinction via SceneryInstance.IsBuilding
(StaticObjectRenderManager.cs:334). Today acdream's loader reads both
arrays into the same WorldEntity pool with no tag, destroying the
distinction (the comment at GameWindow.cs:5175 already acknowledges this
gap for scenery suppression). This commit closes the gap.

Render-time consumption arrives in R2 (EntitySet partition refactor).
Two new LandblockLoader tests lock the tagging behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 11:31:11 +02:00
Erik
a64e6f20da refactor: #100 — remove hiddenTerrainCells / BuildingTerrainCells plumbing
Retired in favour of Task 1's retail-faithful terrain shader Z nudge.
Pure removal — ~50 LOC of dead surface area across:

  - src/AcDream.Core/Terrain/LandblockMesh.cs (drop parameter +
    cell-collapse block)
  - src/AcDream.Core/World/LoadedLandblock.cs (drop field)
  - src/AcDream.Core/World/LandblockLoader.cs (drop method + call)
  - src/AcDream.App/Rendering/GameWindow.cs (3 sites)
  - src/AcDream.App/Streaming/GpuWorldState.cs (6 ctor sites)
  - src/AcDream.App/Streaming/LandblockStreamer.cs (1 ctor site)
  - tests/AcDream.Core.Tests/World/LandblockLoaderTests.cs (drop test)
  - tests/AcDream.Core.Tests/Terrain/LandblockMeshTests.cs (drop test)

No retail anchor — the deleted mechanism never had one; this commit
rolls our code back to the actual retail behaviour established in
the prior commit's shader nudge.

ISSUES.md #100 moved to Recently closed.

Cross-ref:
  docs/research/2026-05-25-issue-100-terrain-cutout-handoff.md
  docs/superpowers/plans/2026-05-25-issue-100-terrain-cutout.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 21:37:53 +02:00
Erik
35b37dfb5f chore(phys): A6.P3 #98 triage — revert neg-poly + bldg-check experiments
Triage step from the plan at C:\Users\erikn\.claude\plans\
i-did-some-work-sharded-acorn.md. Four sessions on issue #98 left the
worktree dirty with ~1352 LOC of mixed work. This commit splits the
work into "keep" (defensible + diagnostic) and "drop" (failed
experiments), then commits the keep set with the drops removed.

Plan asked for three commits (diag / fix / revert); consolidated to one
because the diagnostic emits in TransitionTypes.cs are tightly
interleaved with the multi-sphere CellTransit calls and the CellId
switch. Hunk-level splitting in those files for marginal bisect
granularity didn't justify the misclick risk.

Reverted entirely (failed experiments per slice 7 handoff):
- src/AcDream.Core/Physics/PhysicsDataCache.cs — neg-poly storage
  fields (Stippling, PosSurface, NegSurface, HasNegativeSide,
  IsNegativeSide, NegativeSide).
- src/AcDream.Core/Physics/ShadowObjectRegistry.cs — isBuilding flag
  propagation through Register / ShadowEntry.
- tests/AcDream.Core.Tests/Physics/BSPQueryTests.cs — 165 lines of
  PolygonWithNegativeSide_* tests.
- tests/AcDream.Core.Tests/Physics/ShadowObjectRegistryTests.cs —
  isBuilding propagation tests.
- src/AcDream.Core/World/WorldEntity.cs — IsLandblockBuilding field
  (no consumer once ShadowObjectRegistry.isBuilding is gone).
- src/AcDream.Core/World/LandblockLoader.cs — IsLandblockBuilding=true
  setter on building entities (kept BuildBuildingTerrainCells).
- src/AcDream.App/Rendering/GameWindow.cs — isBuilding: arg passed to
  ShadowObjects.Register.
- src/AcDream.Core/Physics/BSPQuery.cs — TryAdjustWalkableSide /
  IsWalkableAt helpers, their callers, the Path 5 / Path 6 neg-poly
  branch split, the BldgCheck-tied clearCell conditional, and the
  neg-poly ResolveCellPolygons writes.
- src/AcDream.Core/Physics/PhysicsDiagnostics.cs — neg-poly fields
  in the poly-dump format.
- src/AcDream.Core/Physics/TransitionTypes.cs — SpherePath.BldgCheck +
  SpherePath.HitsInteriorCell fields and every consumer, the
  savedBldgCheck try/finally around FindCollisions, and the neg-poly
  format additions to the dump-on-error helper.
- src/AcDream.Core/Physics/CellTransit.cs — FindCellSet overloads
  with hitsInteriorCell out-param and the BuildCellSetAndPickContaining
  out-param threading.

Kept (defensible correctness fixes + diagnostic infrastructure):
- src/AcDream.App/Rendering/GameWindow.cs — render-vs-physics cell
  origin split: the 0.02m render lift no longer leaks into physics
  BSP caching. lb.BuildingTerrainCells threaded into LandblockMesh.Build.
- src/AcDream.Core/World/LoadedLandblock.cs — BuildingTerrainCells
  record field.
- src/AcDream.Core/World/LandblockLoader.cs — BuildBuildingTerrainCells
  (cy*8+cx from LandBlockInfo.Buildings).
- src/AcDream.Core/Terrain/LandblockMesh.cs — hiddenTerrainCells
  param that collapses owned-cell triangles to a zero-area degenerate.
- src/AcDream.App/Streaming/{GpuWorldState,LandblockStreamer}.cs —
  mechanical BuildingTerrainCells threading through LoadedLandblock
  reconstructions.
- src/AcDream.Core/Physics/CellTransit.cs — multi-sphere
  FindTransitCellsSphere variant + multi-sphere AddAllOutsideCells +
  FindCellSet(IReadOnlyList<Sphere>, …) overload + the
  BSPQuery.SphereIntersectsCellBsp call for loaded neighbours. Matches
  retail CObjCell::find_cell_list / CEnvCell::find_transit_cells.
- src/AcDream.Core/Physics/TransitionTypes.cs — multi-sphere FindCellSet
  call site, retail-faithful CellId switch after CheckOtherCells, the
  outdoor-landcell terrain-walkable fallback in CheckOtherCells, and
  the full diagnostic suite ([step-walk], [walkable-nearest],
  [issue98-walkable-detail], [cell-set-summary], LastBspHitPoly
  emits).
- src/AcDream.Core/Physics/PhysicsDiagnostics.cs — ProbeStepWalkEnabled
  gate (ACDREAM_PROBE_STEP_WALK=1) + LogStepWalk helper + FormatVector
  / FormatPlane utilities. All emit-gated.
- src/AcDream.Core/Physics/BSPQuery.cs — diagnostic emits to
  LastBspHitPoly at four sites in SphereIntersectsPolyInternal /
  the placement adjustment path.
- Test files for the kept work: CellTransitFindCellSetTests,
  CellTransitFindTransitCellsSphereTests, PhysicsDiagnosticsTests,
  TransitionCheckOtherCellsTests, LandblockMeshTests,
  LandblockLoaderTests.

Verification:
- dotnet build: green, 0 errors, 3 pre-existing warnings.
- dotnet test: 1156 passed + 8 failed (baseline was 1148 + 8 pre-
  existing; the +8 passing are the new tests for the kept defensible
  work). Same 8 pre-existing failures, no new regressions.

Backup of pre-triage worktree state in stash@{0}.

A6.P3 #98 is still open; this is the apparatus-prep step, not a fix.
Next: cell-dump probe (Step 2 of the plan).
2026-05-23 15:11:49 +02:00
Erik
71d0edc3d7 fix(world #53): namespace stab Ids globally for Tier 1 cache safety
LandblockLoader.BuildEntitiesFromInfo restarted nextId at 1 per landblock,
producing colliding entity.Id values across landblocks. EntityClassificationCache
keys by entity.Id alone, so cross-LB collisions caused cache pollution:
multiple stabs sharing id=1 -> cache entry for id=1 ended up with the
CONCATENATION of multiple entities' batches -> buildings rendered up in the
air with wrong textures (visual gate observation 2026-05-10).

Audit at docs/research/2026-05-10-tier1-mutation-audit.md did not verify
entity.Id uniqueness - that was an unchecked assumption. Cache design
trusted entity.Id was globally unique; for stabs it wasn't.

Fix: optional landblockId parameter on BuildEntitiesFromInfo. When non-zero,
stab Ids are namespaced as 0xC0XXYY00 + nextId, matching the scenery
(0x80XXYY00) and interior (0x40XXYY00) namespacing already in GameWindow.cs.
The 0xC0 top byte distinguishes stabs from those. Existing tests pass
landblockId=0 and keep their legacy starting-from-1 behavior.

Known latent: if any one landblock has >256 stabs, nextId overflows the
low byte. Same pattern + same limitation as scenery/interior. Out of scope
for the immediate Tier 1 cache bug; not affecting current Holtburg play.

Adds 2 regression tests pinning the namespacing + the legacy fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 20:07:19 +02:00
Erik
473a06c534 feat(core): add LandblockLoader with Stab+Building → WorldEntity mapping 2026-04-10 17:58:30 +02:00