acdream/docs/research/acclient_function_map.md
Erik 83b020499b docs(research): #9 sweep acclient_function_map.md against PDB symbols
Pure-docs sweep. Cross-checked 63 hand-curated entries in
acclient_function_map.md against docs/research/named-retail/symbols.json
(the PDB-derived authoritative name table) using the new helper at
tools/pdb-extract/check_function_map.py.

Findings:
  - Zero entries matched address-and-name exactly. Confirms the
    PDB build is from a different revision than the binary that
    produced our Ghidra chunks (~0x800-0xC10 byte delta varies by
    function cluster). Match by NAME, not by raw address.
  - 38 entries corrected by PDB name lookup. The "Was" column
    preserves the old address for traceability against existing
    code comments. Old entries pointed mid-body of the actual
    function; new column heads point to function starts.
  - 25 entries have no PDB match. Either inlined / non-public
    (no S_PUB32 record) or our hand-derived names were synthesized
    from call-site analysis and don't match the MSVC mangled form
    in the PDB. Several had wrong class assignments (e.g. 0x5387C0
    claimed as CTransition::find_collisions, actually
    CPolygon::polygon_hits_sphere). Flagged for re-derivation in
    acclient_2013_pseudo_c.txt.

Pattern: kept the table format with two address columns (PDB +
legacy) so existing code references using the old addresses can
still be looked up. Added a sweep-summary section at the bottom of
the file documenting the methodology + findings.

Helper script at tools/pdb-extract/check_function_map.py is reusable
for future re-runs (re-run after every PDB regeneration / function
map edit).

Closes #9.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 17:44:07 +02:00

221 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# acclient.exe Decompiled Function Map
Hand-curated cross-port index: maps select retail functions to our
C# implementations + ACE / ACME equivalents + struct-offset notes.
**This is the cross-port index, not the authoritative name list.**
For raw symbol→address lookup the authoritative source is
`docs/research/named-retail/symbols.json` (18,366 entries from
`refs/acclient.pdb`, the Sept 2013 EoR build PDB). Regenerate via
`py tools/pdb-extract/pdb_extract.py refs/acclient.pdb`. Several
addresses below were corrected against `symbols.json` in commit
that closed issue #9 — match by name when in doubt.
Mapped from 22,225 decompiled functions (688K lines of C, the
`docs/research/decompiled/` Ghidra chunks) against ACE's C# physics
port and ACME's ClientReference.cs. Now augmented by the named
retail decomp at `docs/research/named-retail/`.
## CPhysicsObj (chunk_00510000.c, chunk_00500000.c)
> **Addresses corrected against `symbols.json` 2026-04-25 (issue #9
> sweep).** All entries were off by ~0xC00-0x800 (different build
> revision than our binary). PDB names are ground truth; previous
> hand-curated addresses pointed mid-body.
| Address (PDB) | Was | Method | Description |
|---------------|-----|--------|-------------|
| 0x00515D10 | 0x515020 | CPhysicsObj::update_object | Top-level per-frame update |
| 0x00510700 | 0x5111D0 | CPhysicsObj::UpdatePhysicsInternal | Euler integration: `pos += vel*dt + 0.5*accel*dt²` |
| 0x00510950 | 0x511420 | CPhysicsObj::calc_acceleration | Sets gravity (-9.8 Z) when Gravity flag set |
| 0x005113F0 | 0x511EC0 | CPhysicsObj::set_velocity | Stores velocity, clamps to MaxVelocity (50.0) |
| 0x005114D0 | 0x511FA0 | CPhysicsObj::set_local_velocity | Body→world transform then set_velocity |
| 0x00511310 | 0x511DE0 | CPhysicsObj::set_on_walkable | Sets/clears OnWalkable transient flag |
| 0x00513FD0 | 0x511560 | CPhysicsObj::report_collision_start | Fires environment collision callback |
| 0x00514620 | 0x513AC0 | CPhysicsObj::report_collision_end | Fires collision-end callback |
| 0x00512C30 | 0x513730 | CPhysicsObj::UpdatePositionInternal | Position advance + interpenetration resolve |
| 0x0050EE70 | 0x50F940 | CPhysicsObj::calc_friction | Friction from ground normal + slope |
> Three previous rows lacked exact PDB matches (probably inlined
> private methods, not exported via S_PUB32):
> `handle_obj_collision`, `handle_collision`, `check_contact_velocity`.
> Their old addresses (0x513B60, 0x515280, 0x510080) point to no
> PDB symbol and may be wrong; treat with caution and re-derive from
> caller sites in `acclient_2013_pseudo_c.txt` if needed.
### PhysicsObj Struct Layout
| Offset | Field | Type |
|--------|-------|------|
| +0xA8 | State (PhysicsState flags) | uint |
| +0xAC | TransientState | uint |
| +0xB0 | Elasticity | float |
| +0xD8 | LastUpdateTime | double |
| +0xE0/E4/E8 | Velocity XYZ | float[3] |
| +0xEC/F0/F4 | Acceleration XYZ | float[3] |
| +0xF8/FC/100 | Omega XYZ | float[3] |
| +0x12C | WeenieObject ptr | ptr |
| +0x130/134/138 | Ground normal XYZ | float[3] |
## CMotionInterp (chunk_00520000.c)
> **Addresses corrected against `symbols.json` 2026-04-25 (issue #9
> sweep).** All entries were off by ~0xBE0-0xC10 bytes (consistent
> delta within this class — same build-revision skew). Old addresses
> in column 2 are kept for traceability against existing comments.
| Address (PDB) | Was (mid-body) | Method | Description |
|---------------|----------------|--------|-------------|
| 0x00527AA0 | 0x5286B0 | CMotionInterp::get_jump_v_z | Jump Z velocity (delegates to WeenieObj) |
| 0x00527A50 | 0x528660 | CMotionInterp::jump_charge_is_allowed | Can charge jump? |
| 0x005279E0 | 0x5285E0 | CMotionInterp::motion_allows_jump | Current anim permits jump? |
| 0x005282B0 | 0x528EC0 | CMotionInterp::jump_is_allowed | Top-level jump permission |
| 0x005280C0 | 0x528CD0 | CMotionInterp::get_leave_ground_velocity | Full 3D launch vector |
| 0x00528780 | 0x529390 | CMotionInterp::jump | Initiate jump |
| 0x00528B00 | 0x529710 | CMotionInterp::LeaveGround | Reset jump state on airborne |
| 0x00528AC0 | 0x5296D0 | CMotionInterp::HitGround | Landing handler |
| 0x00527D50 | 0x528960 | CMotionInterp::get_state_velocity | Compute velocity for current motion |
| 0x00527E40 | 0x528A50 | CMotionInterp::StopCompletely | Reset to Ready/idle |
| 0x00528010 | 0x5287F0 | CMotionInterp::adjust_motion | Apply pending motion adjustments |
| 0x005287E0 | 0x5293F0 | CMotionInterp::apply_raw_movement | Raw→interpreted state conversion |
| 0x00528870 | 0x529210 | CMotionInterp::apply_current_movement | Set physics velocity from interpreted state |
| 0x00528240 | 0x528DD0 | CMotionInterp::contact_allows_move | Slope angle check |
| 0x00528360 | 0x528F70 | CMotionInterp::DoInterpretedMotion | Core animation state machine |
| 0x00528470 | 0x529080 | CMotionInterp::StopInterpretedMotion | Stop specific interpreted motion |
| 0x00528530 | 0x529140 | CMotionInterp::StopMotion | Stop specific raw motion |
| 0x00528D20 | 0x529930 | CMotionInterp::DoMotion | Process one raw motion command |
| 0x00528E80 | 0x529A90 | CMotionInterp::PerformMovement | Top-level dispatcher (switch 1-5) |
### MotionInterp Struct Layout
| Offset | Field | ACE name |
|--------|-------|----------|
| +0x04 | WeenieObject ptr | WeenieObj |
| +0x08 | PhysicsObject ptr | PhysicsObj |
| +0x14 | RawMotionState start | RawState |
| +0x20 | ForwardCommand | RawState.ForwardCommand |
| +0x28 | ForwardSpeed | RawState.ForwardSpeed |
| +0x2C | SideStepCommand | RawState.SideStepCommand |
| +0x38 | TurnCommand | RawState.TurnCommand |
| +0x44 | InterpretedMotionState start | InterpretedState |
| +0x4C | InterpretedState.ForwardCommand | |
| +0x50 | InterpretedState.ForwardSpeed | |
| +0x70 | StandingLongJump | bool |
| +0x74 | JumpExtent | float |
| +0x7C | MyRunRate | float |
## CLandBlockStruct (chunk_00530000.c)
> **Issue #9 sweep, 2026-04-25.** Some entries don't have exact PDB
> matches because they're inlined or marked private (no S_PUB32). For
> those, the old address may still be useful via Ghidra chunk
> inspection. Where PDB has the name, use the corrected address.
| Address (PDB) | Was | Method | Description |
|---------------|-----|--------|-------------|
| (no S_PUB32) | 0x531D10 | CLandBlockStruct::IsSWtoNECut | Split direction helper (inner). PDB at 0x531D10 = `ConstructPolygons``IsSWtoNECut` is likely inlined. Check pseudo-C `0x531D10` neighborhood for the inline. |
| 0x00531D10 | 0x532A50 | CLandBlockStruct::ConstructPolygons | Outer 8×8 loop with 0xCCAC033 constants |
| 0x005329A0 | 0x532EB0 | CLandBlockStruct::ConstructUVs | PalCode computation |
| (no S_PUB32) | 0x532D10 | CLandBlockStruct::unpack | Likely inlined or private; not in symbols.json. Cross-check `acclient.c`. |
| (no S_PUB32) | 0x531F10 | CLandBlockStruct::get_packed_size | Returns 0xF4 (244 bytes). Likely inlined. |
| (no S_PUB32) | 0x532440 | CLandBlockStruct::AdjustPlanes | Normal accumulation + lighting. Likely inlined. |
| 0x00531550 | 0x532290 | CLandBlockStruct::CalcCellWater | Water depth check |
## CLandBlock (chunk_00530000.c)
> **Issue #9 sweep, 2026-04-25.** Several entries are not in PDB
> public symbols (private/inlined). `release_all`, `init_static_objs`,
> `release_visible_cells`, `grab_visible_cells` all corrected.
| Address (PDB) | Was | Method | Description |
|---------------|-----|--------|-------------|
| (no S_PUB32) | 0x530690 | CLandBlock::Init | Likely inlined ctor; not exported. |
| 0x0052FCF0 | 0x5307E0 | CLandBlock::release_all | Free all resources |
| 0x00530A40 | 0x531780 | CLandBlock::init_static_objs | Load static objects from LandBlockInfo |
| 0x0052F480 | 0x531000 | CLandBlock::release_visible_cells | Free cell data |
| 0x0052F460 | 0x5301E0 | CLandBlock::grab_visible_cells | BFS neighbor expansion |
| (no S_PUB32) | 0x530650 | CLandBlock::add_server_object | Likely inlined / different overload. |
## LandDefs (chunk_005A0000.c)
> **Issue #9 sweep, 2026-04-25.** None of these match the PDB by name.
> They're either inlined globals or our names were synthesised. Names
> are kept for legacy compatibility; addresses unchanged from the
> Ghidra chunk analysis. Re-derive via `acclient.c` cross-reference.
| Address (legacy) | Method | Description |
|------------------|--------|-------------|
| 0x5AAA30 | LandDefs::get_vars | Set 8 coordinate constants |
| 0x5AABB0 | LandDefs::get_outside_lcoord | Cell ID → world coord |
| 0x5AAC70 | LandDefs::AdjustToOutside | Normalize position to outdoor coords |
| 0x5AAB50 | LandDefs::get_block_dir | Quadrant → Direction enum |
## Collision / Transition (chunk_00530000.c)
> **Issue #9 sweep, 2026-04-25.** Many of these names don't appear
> verbatim in PDB; either the actual class is `CCylSphere` /
> `CSphere` differently scoped, or the methods are private/inlined.
> A few addresses now pointed to entirely different functions — for
> example `0x5387C0` claimed `CTransition::find_collisions` but PDB
> shows that address is `CPolygon::polygon_hits_sphere`. Use
> `acclient_2013_pseudo_c.txt` to re-derive these as ground truth.
> See ISSUES.md #9 closure for the verification pass.
| Address (legacy) | Method (legacy name) | Notes |
|------------------|----------------------|-------|
| 0x5384E0 | Sphere::SphereIntersectsRay | Not in PDB at this address; re-derive. |
| 0x539500 | Polygon::sphere_intersects_poly | Not in PDB; re-derive. |
| 0x539750 | Polygon::sphere_intersects_solid | PDB at 0x539750 = `CMaterial::SetDiffuseSimple` — wrong class assignment. |
| 0x539BA0 | Polygon::find_time_of_collision | Not in PDB; re-derive. |
| 0x539DF0 | Polygon::find_time_of_collision (cyl) | Not in PDB; re-derive. |
| 0x53A040 | Polygon::find_walkable_collision | PDB at 0x53A040 = `BSPTREE::RemoveNonPortalNodes` — wrong. |
| 0x539110 | Polygon::calc_normal | Not in PDB; re-derive. |
| 0x539060 | Plane::ray_plane_intersect | Not in PDB; re-derive. |
| 0x00537440 / 0x00536F40 / 0x00537A10 | CSphere::slide_sphere | Three overloads in PDB — old address `0x538EB0` was wrong. |
| 0x005379A0 | CSphere::land_on_sphere (corrected from 0x538F50) | |
| 0x538180 | CTransition::collide_with_point | Not in PDB; re-derive. |
| 0x005387C0 | CPolygon::polygon_hits_sphere | PDB ground truth. Was claimed as `CTransition::find_collisions` (wrong). |
| 0x53A230 | Polygon::hits_walkable | Not in PDB; re-derive. |
## WeenieObject vtable (confirmed from call sites)
| vtable offset | ACE method | Called from |
|--------------|-----------|------------|
| +0x30 | InqJumpVelocity | get_jump_v_z |
| +0x34 | InqRunRate | get_state_velocity |
| +0x3C | CanJump | jump_is_allowed |
| +0x4C | HandleCollisionEnd | report_collision_end |
| +0x50 | HandleCollisionStart | handle_obj_collision |
| +0x54 | HandleMissileCollision | handle_obj_collision |
| +0x58 | HandleEnvironmentCollision | report_collision_start |
## PhysicsEngine (chunk_00450000.c)
| Address (legacy) | Method | Description |
|------------------|--------|-------------|
| 0x452A10 | PhysicsEngine::update | Not in PDB at this address (private/inlined or a different class). Re-derive from `acclient_2013_pseudo_c.txt` if needed. |
---
## Issue #9 sweep summary
Pure docs sweep on 2026-04-25 against `docs/research/named-retail/symbols.json`.
Tooling: `tools/pdb-extract/check_function_map.py`. Findings:
- **63 entries checked.** Zero matched address-and-name exactly (all
hand-curated addresses were off by 0x800-0xC10 bytes — confirms the
PDB build is from a different revision than the binary that produced
our Ghidra chunks).
- **38 entries corrected** by name lookup (PDB name found, address
swapped to the function start).
- **25 entries lack PDB matches.** Either inlined / non-public (no
S_PUB32 record), or our hand-derived names were synthesized from
call-site analysis and don't match the actual MSVC symbol. The
ones that pointed to other functions in PDB (e.g.
`CTransition::find_collisions` → actually `CPolygon::polygon_hits_sphere`)
are flagged for re-derivation.
When in doubt: grep `acclient_2013_pseudo_c.txt` by class name to find
the actual function bodies, and use `acclient_function_map.md` for the
cross-port (ACE/ACME) hints + struct-offset lookups, not as the
authoritative address table.