fix(cdb): A6.P1 — a6-probe.cdb v4 hex-bits floats
v3 with @@c++(*(float*)..) STILL produced 0.000000 across the board.
Conclusion: cdb's .printf %f is unreliable for our use case — possibly
doesn't handle the float-to-double promotion in varargs the way C
printf does, or has a deeper limitation we don't have time to debug.
Pivoting to: print all floats as 32-bit hex bits via %08X, reinterpret
in the Python analysis pipeline via struct.unpack('<f', bytes.fromhex(...))
to recover IEEE 754 single-precision values.
This bypasses cdb's float formatting entirely. Integer reads (which
work — substeps, insertType, collide flag, isWater) stay as %d.
The smoking gun: BP6's check_walkable threshold should be 0.0871556997
(cos 85°) per the decomp call site at acclient_2013_pseudo_c.txt:273202.
v4's BP6 should output threshold_h=0x3DB283D7. If it does, the
infrastructure is sound and we can proceed to all 9 scenarios.
v3 capture preserved as retail-v3-cpp-zero-floats.log audit trail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1b6d49ea57
commit
2d841cb615
2 changed files with 35384 additions and 46 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1,19 +1,18 @@
|
|||
$$
|
||||
$$ Phase A6.P1 cdb probe spike v3 — 2026-05-21
|
||||
$$ Phase A6.P1 cdb probe spike v4 — 2026-05-21
|
||||
$$
|
||||
$$ v3 changes (from v2 dry-run lesson):
|
||||
$$ - All float reads now use @@c++(*(float*)addr) instead of dwo(addr).
|
||||
$$ cdb's MASM evaluator treats dwo() as a 32-bit integer, which then
|
||||
$$ prints as 0.000000 when passed to .printf %f (which expects double).
|
||||
$$ The @@c++ expression forces C++ interpretation, dereferencing the
|
||||
$$ address as a float pointer, producing a proper float that printf %f
|
||||
$$ can format. v2 hit counts were correct but all %f values were 0.
|
||||
$$ - Integer reads (%d) still use dwo() — that works.
|
||||
$$ v4 changes (after v3 still produced 0.000000 for all floats):
|
||||
$$ - All float fields output as 32-bit hex via %08X. Analysis side
|
||||
$$ (Python) reinterprets bytes via struct.unpack('<f', bytes.fromhex(...))
|
||||
$$ to get the IEEE 754 single-precision value.
|
||||
$$ - This bypasses cdb .printf's apparently-broken %f handling entirely.
|
||||
$$ v2 used dwo() + %f (zeros). v3 used @@c++(*(float*)..) + %f (also
|
||||
$$ zeros). %X with dwo() returns the raw 32-bit value, which we know
|
||||
$$ works because the integer reads (substeps, insertType) produced
|
||||
$$ real values in v2/v3.
|
||||
$$
|
||||
$$ v2 changes (from v1 dry-run):
|
||||
$$ - All struct offsets verified against PDB via dt acclient!TYPENAME.
|
||||
$$ - BP6 symbol fixed: CTransition::check_walkable.
|
||||
$$ - Stack-arg reads use [esp+N] with proper double-indirect.
|
||||
$$ v3 changes (history): added @@c++(*(float*)...) for floats — didn't help.
|
||||
$$ v2 changes (history): fixed all offsets via PDB dt dump + BP6 symbol.
|
||||
$$
|
||||
$$ Calling convention: all functions __thiscall. ecx = this; non-this
|
||||
$$ args at [esp+4], [esp+8], [esp+0xC] in order, after the return
|
||||
|
|
@ -22,13 +21,15 @@ $$
|
|||
$$ Field offsets used (from PDB dt dump):
|
||||
$$ Plane: N.x +0x00, N.y +0x04, N.z +0x08, d +0x0c
|
||||
$$ CSphere: center.x +0x00, .y +0x04, .z +0x08, radius +0x0c
|
||||
$$ CPolygon: plane +0x20 (so plane.N.x = polygon+0x20, .d = +0x2c)
|
||||
$$ SPHEREPATH: collide +0x104, insert_type +0x154,
|
||||
$$ walkable_allowance +0x1b8, walk_interp +0x1bc
|
||||
$$ CTransition:object_info +0x000, sphere_path +0x020,
|
||||
$$ (so sphere_path.collide = trans+0x124,
|
||||
$$ sphere_path.insert_type = trans+0x174,
|
||||
$$ sphere_path.walkable_allowance = trans+0x1d8)
|
||||
$$ CPolygon: plane +0x20
|
||||
$$ SPHEREPATH: collide +0x104, insert_type +0x154, walk_interp +0x1bc,
|
||||
$$ walkable_allowance +0x1b8
|
||||
$$ CTransition:object_info +0x000, sphere_path +0x020
|
||||
$$ (sphere_path.walk_interp = trans+0x1dc)
|
||||
$$
|
||||
$$ Output format for floats: name_h=0xHHHHHHHH (lowercase _h suffix
|
||||
$$ marks "hex bits, reinterpret as IEEE 754 single"). E.g. BP6's
|
||||
$$ threshold value 0.0871556997 = 0x3DB283D7.
|
||||
$$
|
||||
|
||||
.logopen /t a6-probe-${ARG_LOG_TAG}.log
|
||||
|
|
@ -36,7 +37,6 @@ $$
|
|||
.symopt+ 0x40
|
||||
.reload /f acclient.exe
|
||||
|
||||
$$ Counters: $t0 = total hits, $t1..$t7 = per-BP hits
|
||||
r $t0 = 0
|
||||
r $t1 = 0
|
||||
r $t2 = 0
|
||||
|
|
@ -47,44 +47,28 @@ r $t6 = 0
|
|||
r $t7 = 0
|
||||
|
||||
$$ BP1: CTransition::transitional_insert(this, sub_step_count)
|
||||
$$ ecx = CTransition*; [esp+4] = sub_step_count (int)
|
||||
$$ read: sub_step_count (int), sphere_path.insert_type (int) at trans+0x174
|
||||
$$ All integer fields; no @@c++ needed.
|
||||
bp acclient!CTransition::transitional_insert "r $t1 = @$t1 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP1] transitional_insert hit#%d substeps=%d insertType=%d\\n\", @$t1, dwo(@esp+4), dwo(@ecx+0x174); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP2: CTransition::step_up(this, step_up_normal)
|
||||
$$ ecx = CTransition*; [esp+4] = Vector3* step_up_normal
|
||||
$$ read: walkable_allowance (float at trans+0x1d8), step_up_normal.z (float via arg)
|
||||
bp acclient!CTransition::step_up "r $t2 = @$t2 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP2] step_up hit#%d walkAllow=%f normalZ=%f\\n\", @$t2, @@c++(*(float*)(@ecx+0x1d8)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+8)); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
bp acclient!CTransition::step_up "r $t2 = @$t2 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP2] step_up hit#%d walkAllow_h=0x%08X normalZ_h=0x%08X\\n\", @$t2, dwo(@ecx+0x1d8), dwo(poi(@esp+4)+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP3: SPHEREPATH::set_collide(this, collision_normal)
|
||||
$$ ecx = SPHEREPATH*; [esp+4] = Vector3* collision_normal
|
||||
$$ read: normal.x, .y, .z (floats via arg)
|
||||
bp acclient!SPHEREPATH::set_collide "r $t3 = @$t3 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP3] set_collide hit#%d nx=%f ny=%f nz=%f\\n\", @$t3, @@c++(*(float*)(*(unsigned int*)(@esp+4)+0)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+4)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+8)); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
bp acclient!SPHEREPATH::set_collide "r $t3 = @$t3 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP3] set_collide hit#%d nx_h=0x%08X ny_h=0x%08X nz_h=0x%08X\\n\", @$t3, dwo(poi(@esp+4)+0), dwo(poi(@esp+4)+4), dwo(poi(@esp+4)+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP4: BSPTREE::find_collisions(this, transition, walkable_allowance)
|
||||
$$ ecx = BSPTREE*; [esp+4] = CTransition*; [esp+8] = float walkable_allowance (by-value!)
|
||||
$$ read: trans.sphere_path.collide (int via arg2+0x124),
|
||||
$$ trans.sphere_path.insert_type (int via arg2+0x174),
|
||||
$$ walkable_allowance (float by-value at esp+8)
|
||||
bp acclient!BSPTREE::find_collisions "r $t4 = @$t4 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP4] find_collisions hit#%d collide=%d insertType=%d walkAllow=%f\\n\", @$t4, dwo(poi(@esp+4)+0x124), dwo(poi(@esp+4)+0x174), @@c++(*(float*)(@esp+8)); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
bp acclient!BSPTREE::find_collisions "r $t4 = @$t4 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP4] find_collisions hit#%d collide=%d insertType=%d walkAllow_h=0x%08X\\n\", @$t4, dwo(poi(@esp+4)+0x124), dwo(poi(@esp+4)+0x174), dwo(@esp+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP5: CPolygon::adjust_sphere_to_plane(this, sphere_path, sphere, movement)
|
||||
$$ ecx = CPolygon*; [esp+4] = SPHEREPATH*; [esp+8] = CSphere*; [esp+0xC] = Vector3* movement
|
||||
$$ THE OVER-CORRECTION SUSPECT. Captures EVERY arg field as float for paired delta analysis.
|
||||
bp acclient!CPolygon::adjust_sphere_to_plane "r $t5 = @$t5 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP5] adjust_sphere hit#%d Nx=%f Ny=%f Nz=%f d=%f cx=%f cy=%f cz=%f r=%f winterp=%f mvx=%f mvy=%f mvz=%f\\n\", @$t5, @@c++(*(float*)(@ecx+0x20)), @@c++(*(float*)(@ecx+0x24)), @@c++(*(float*)(@ecx+0x28)), @@c++(*(float*)(@ecx+0x2c)), @@c++(*(float*)(*(unsigned int*)(@esp+8)+0)), @@c++(*(float*)(*(unsigned int*)(@esp+8)+4)), @@c++(*(float*)(*(unsigned int*)(@esp+8)+8)), @@c++(*(float*)(*(unsigned int*)(@esp+8)+0xc)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+0x1bc)), @@c++(*(float*)(*(unsigned int*)(@esp+0xc)+0)), @@c++(*(float*)(*(unsigned int*)(@esp+0xc)+4)), @@c++(*(float*)(*(unsigned int*)(@esp+0xc)+8)); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
$$ 13 floats: plane.N + plane.d + sphere.center + sphere.radius + walk_interp + movement.xyz
|
||||
bp acclient!CPolygon::adjust_sphere_to_plane "r $t5 = @$t5 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP5] adjust_sphere hit#%d Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X cx_h=0x%08X cy_h=0x%08X cz_h=0x%08X r_h=0x%08X winterp_h=0x%08X mvx_h=0x%08X mvy_h=0x%08X mvz_h=0x%08X\\n\", @$t5, dwo(@ecx+0x20), dwo(@ecx+0x24), dwo(@ecx+0x28), dwo(@ecx+0x2c), dwo(poi(@esp+8)+0), dwo(poi(@esp+8)+4), dwo(poi(@esp+8)+8), dwo(poi(@esp+8)+0xc), dwo(poi(@esp+4)+0x1bc), dwo(poi(@esp+0xc)+0), dwo(poi(@esp+0xc)+4), dwo(poi(@esp+0xc)+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP6: CTransition::check_walkable(this, threshold)
|
||||
$$ ecx = CTransition*; [esp+4] = float threshold (by-value)
|
||||
$$ Expected: ~0.0871556997 (cos 85°) per decomp at line 273202.
|
||||
bp acclient!CTransition::check_walkable "r $t6 = @$t6 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP6] check_walkable hit#%d threshold=%f\\n\", @$t6, @@c++(*(float*)(@esp+4)); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
$$ Expected threshold_h = 0x3DB283D7 (= 0.0871556997, cos 85°) per decomp.
|
||||
bp acclient!CTransition::check_walkable "r $t6 = @$t6 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP6] check_walkable hit#%d threshold_h=0x%08X\\n\", @$t6, dwo(@esp+4); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
$$ BP7: COLLISIONINFO::set_contact_plane(this, plane, is_water)
|
||||
$$ ecx = COLLISIONINFO*; [esp+4] = Plane*; [esp+8] = int is_water
|
||||
$$ read: plane.N + plane.d (floats via arg2), is_water (int via arg3)
|
||||
bp acclient!COLLISIONINFO::set_contact_plane "r $t7 = @$t7 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP7] set_contact_plane hit#%d Nx=%f Ny=%f Nz=%f d=%f isWater=%d\\n\", @$t7, @@c++(*(float*)(*(unsigned int*)(@esp+4)+0)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+4)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+8)), @@c++(*(float*)(*(unsigned int*)(@esp+4)+0xc)), dwo(@esp+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
bp acclient!COLLISIONINFO::set_contact_plane "r $t7 = @$t7 + 1; r $t0 = @$t0 + 1; .printf /D \"[BP7] set_contact_plane hit#%d Nx_h=0x%08X Ny_h=0x%08X Nz_h=0x%08X d_h=0x%08X isWater=%d\\n\", @$t7, dwo(poi(@esp+4)+0), dwo(poi(@esp+4)+4), dwo(poi(@esp+4)+8), dwo(poi(@esp+4)+0xc), dwo(@esp+8); .if (@$t0 >= 50000) { qd } .else { gc }"
|
||||
|
||||
.printf "a6-probe v3 armed: BPs 1-7 set with PDB-verified offsets + C++ float reads, threshold=50000 total hits, qd on threshold\n"
|
||||
.printf "a6-probe v4 armed: hex-bits float output, threshold=50000 total hits\\n"
|
||||
|
||||
$$ Continue execution
|
||||
g
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue