# Research task — Retail AC: cell transitions, underground/dungeons, and seamless inside/outside rendering > **Shared prompt for a multi-model study (2026-06-02).** The same prompt is run on > several models (Opus 4.6/4.7/4.8, Sonnet 4.6, and an external model) so we can compare > independent reads before committing to an architecture. Study the **source** (retail > decomp + reference repos) and **cite everything** — do not guess. Depth + citations > matter far more than brevity. ## 0. Why this study exists (context) **acdream** is a modern C# .NET port of the retail Asheron's Call client (Sept 2013 EoR build). The rule: *the code is modern, the behavior is retail.* Every AC-specific algorithm is ported faithfully from the named retail decomp. We are at an architecture decision and want ground truth before choosing. Two coupled problems: 1. **Cell-membership flicker (physics).** The player's "current cell" ping-pongs at boundaries — at a near-static position the cell flips e.g. `0xA9B40170` (indoor cottage vestibule) ↔ `0xA9B40031` (outdoor landcell) every physics tick, and also `vestibule ↔ room` and inside the cellar. Root finding so far: acdream runs retail's collision *sweep* but then **discards the swept cell** and **re-derives the cell from the final static position every tick** (`PhysicsEngine.ResolveCellId`), which flips as the collision push-back jitters the end position ±~8 cm across the boundary. 2. **Non-seamless indoor render.** Standing inside a cottage/cellar the interior does not seal: the ceiling isn't capped, the doorway opening shows the blue clear-color instead of the real outside (no sky / no rain visible through the door), entities/particles bleed through walls, and at the threshold the view strobes between "indoor (incomplete)" and "outdoor." acdream's render maintains its **own** cell/visibility system separate from physics; we believe retail renders inside+outside seamlessly through a single portal-visibility traversal. We have a candidate fix direction ("track the cell through the transition sweep like retail's `validate_transition` + `change_cell`, drop the static re-derive, add the `do_not_load_cells` prune, and make the render obey one portal-visibility traversal"), but we want a **solid, decomp-grounded understanding of how retail ACTUALLY does all of this** before we commit — patches/guesses in this exact area have failed ~10× historically. ## 1. Your deliverable A comprehensive, decomp-cited markdown report. For **every** non-trivial claim, cite the retail function **name + address** (from the decomp) or the reference **file:line** you verified it from. Include short pseudocode where it clarifies control flow. End with a concrete "Recommended acdream architecture" section (questions D14–16). Write your report to the output path given to you (e.g. `docs/research/2026-06-02-retail-cell-render-study-.md`). ## 2. Sources to study **Primary oracle — the retail decomp (study this first and most):** - `docs/research/named-retail/acclient_2013_pseudo_c.txt` — 1.4 M lines of named pseudo-C. Grep by `Class::method` (e.g. `CTransition::validate_transition`). - `docs/research/named-retail/acclient.h` — verbatim retail struct definitions. - `docs/research/named-retail/symbols.json` — name ↔ address index (grep by name or addr). **Reference repos (cross-check at least two per topic; the intersection is usually truth):** - `references/ACE/` — server-side C# physics port. `Source/ACE.Server/Physics/` has `Common/` (ObjCell, EnvCell, LandCell, Position), `Animation/` and the transition/ sphere-path/cell logic. Authoritative C# reading of `find_cell_list`, `change_cell`, `Transition`, `SpherePath`. - `references/ACViewer/` — MonoGame client that renders world + dungeons. `Physics/Common/` (EnvCell, ObjCell, CellArray) and `Render/` (how cells/portals are drawn). - `references/WorldBuilder/` — the render base acdream extracted from. EnvCell/portal/ visibility/scenery managers; how it draws interiors + the (flat-stencil) inside/outside split it uses. - `references/Chorizite.ACProtocol/`, `references/AC2D/`, `references/holtburger/` — use as relevant (struct field order, simpler client confirmations). **acdream's current code (so your synthesis is actionable, not abstract):** - `src/AcDream.Core/Physics/PhysicsEngine.cs` — `ResolveCellId` (~:272), `ResolveWithTransition` (~:651, see the two `ResolveCellId(sp.GlobalSphere[0].Origin,…)` calls at ~:909/:928 that discard the swept cell). - `src/AcDream.Core/Physics/CellTransit.cs` — `FindCellList`/`FindCellSet`/`BuildCellSetAndPickContaining`, `FindTransitCellsSphere`, `AddAllOutsideCells`, `CheckBuildingTransit` (note: NO `do_not_load_cells` prune today). - `src/AcDream.Core/Physics/TransitionTypes.cs` — `SpherePath` (`CheckCellId`/`CheckPos`, only set at `InitPath`/reset — NOT advanced through the sweep), `Transition` (`FindEnvCollisions`, `CheckOtherCells`). - `src/AcDream.Core/World/Cells/` — the W1 unified cell graph (`ObjCell`/`EnvCell`/`LandCell`/`CellGraph`/`CellPortal`). - `src/AcDream.App/Rendering/CellVisibility.cs` + `PortalVisibilityBuilder.cs` + `GameWindow.cs` (terrain/shell/entity draw gates ~:7150–7420). ## 3. Decomp anchors (verified starting points — confirm and expand; find more yourself) Physics / cell tracking: - `CPhysicsObj::change_cell` @ `0x00513390` (pseudo_c ~:281192) — the leave/enter setter. - `CPhysicsObj::SetPositionInternal` @ `0x00515330` (~:283399) — reads `arg2->sphere_path.curr_cell`, calls `change_cell` only when it differs. - `CTransition::validate_transition` @ `0x0050aa70` (~:272547) — advances `sphere_path.curr_cell = check_cell` on an accepted move (~:272608-272619); resets to `curr_cell` on a block/slide (~:272593). - `CTransition::check_collisions` @ `0x0050aa00` (~:272530); `CTransition::check_other_cells` @ `0x0050ae50` (~:272717) — calls `find_cell_list`. - `CTransition::transitional_insert` @ `0x0050b6f0` (~:273137) — the sweep stepper. - `CObjCell::find_cell_list` @ `0x0052b4e0` (~:308742) — builds the cell array, picks the containing cell (`*arg5`), applies the `do_not_load_cells` prune (~:308829-308867). - `CObjCell::GetVisible` (pseudo_c ~:308209) magnitude dispatch; `CEnvCell::GetVisible`, `CLandCell::GetVisible`, `CLandCell::add_all_outside_cells`, `CObjCell::point_in_cell` (vtable +0x84), `CEnvCell::find_transit_cells`. Cell structs (acclient.h): `CObjCell` (:30915), `CEnvCell` (:32072), `CLandCell` (:31886), `CSortCell` (:31880), `CCellPortal` (:32300), `CBldPortal` (:32094), `CellStruct` (:32275), plus `SPHEREPATH`, `CELLARRAY`, `Position`. Rendering / visibility (verify addresses; these are from prior notes): - `ConstructView` (~:433750 / :433827), `InitCell` (~:432896), `CObjCell::find_visible_child_cell` (~:311397). Find the full PVS/PView traversal, the EnvCell draw path, how exit portals / `seen_outside` feed render, terrain/sky gating. ## 4. Questions to answer (be comprehensive + cited) ### A. Cell membership & transitions (physics) 1. How does retail represent and store "the cell I'm in" (`curr_cell`)? When/where is it updated? Trace the full chain: per-step sweep → `find_cell_list` → `validate_transition` advance → `SetPositionInternal`/`change_cell`. 2. Exactly how does `find_cell_list` build the candidate cell array, and how does it pick the single containing cell (`*arg5`)? What is the `do_not_load_cells` prune — when is it set, what does it remove, and what stability does it buy? 3. **Precisely how does retail avoid cell flicker** at a doorway / indoor↔outdoor / room↔room? Is it directed portal-crossing, swept-path containment with accept-on-move, the prune, `point_in_cell` semantics, or a combination? What guarantees a blocked/standing-still step does NOT change the cell? 4. How does a player transition indoor→outdoor (exit) and outdoor→indoor (enter)? Between interior cells? What do `CCellPortal` vs `CBldPortal` do, and how does the exit portal / outdoor landcell get added and chosen? 5. Is the cell ARRAY (for collision) the same mechanism as `curr_cell` (membership), or two? How do they relate within one transition? ### B. Underground / dungeons 6. How are dungeons represented in the dats and at runtime — EnvCell graph, portals, the absence of terrain? How does this differ from building interiors (cottage/inn) which sit ON a landblock with terrain? 7. How does the player move through a dungeon: cell tracking, dungeon cell loading/streaming, and how the engine knows there is no sky/terrain to draw? 8. Is there an explicit "underground" flag/state (e.g. on `Position`/landblock/cell), or is "underground" simply "current cell is an EnvCell with no outdoor reachability"? Cite the flag/field if it exists. ### C. Rendering inside and outside (the seamless seal) 9. Trace retail's render visibility: how does it build the visible set in ONE pass (`ConstructView`/`InitCell`/`find_visible_child_cell`/PVS/PView)? What does it output (visible cell list, per-portal clip regions/frustum)? 10. How does retail draw the OUTSIDE seen through a doorway/window from inside (sky, rain, terrain, exterior buildings) so there is **no blue clear-color hole**? How are exit portals / `seen_outside` handled in the render traversal? 11. How does retail seal interiors — cap ceilings, prevent the outdoor world from bleeding in, and clip entities/particles to the visible cells? 12. How does retail decide to draw terrain + sky vs not, as a function of the current cell (indoor / outdoor / underground)? 13. **Is the render cell/visibility the SAME `curr_cell`/cell-graph as physics, or separate?** Trace whether render reads the physics `curr_cell` and traverses the shared cell graph, or maintains its own. (Central to acdream's decision.) ### D. Synthesis for acdream (be concrete) 14. Given acdream re-derives membership statically per tick (instead of tracking it through the sweep) and renders with a separate cell system, what is the **retail-faithful target architecture** we should port? 15. Specifically: should membership be advanced inside the transition sweep (port `validate_transition`'s `curr_cell` advance + the `do_not_load_cells` prune + drop the static `ResolveCellId`, reading `sphere_path.curr_cell` like `SetPositionInternal`)? Should the render obey the physics `curr_cell` + a single portal-visibility traversal? Justify from the decomp. 16. List the **must-port functions** (with decomp addresses), the integration order, the main risks (esp. anything touching the collision sweep where acdream has a history of bugs), and what conformance tests would prove faithfulness. ## 5. Method reminders - Grep the named decomp by `Class::method` FIRST; confirm addresses in `symbols.json`. - The decomp is ground truth; ACE/ACViewer/WorldBuilder are interpretation aids — when they disagree, the decomp wins, but note the disagreement. - Distinguish what you VERIFIED in source from what you INFER. Flag inferences. - Cite: `function_name @ 0xADDR (pseudo_c:LINE)` or `repo/path/File.cs:LINE`.