re: a deeper window does not help -- the 0x820af844 object is not the definition record
Dumping 512 words instead of 96 finds exactly the same 4 of ~50 disc values, for all five correlated units, so the rest of the record is not in this structure. Also corrects the reason recorded last commit: get_f32 is NOT unreliable on default-heavy records -- it resolves 46-57 numeric fields per unit, which is what made the emptiness of the correlation measurable in the first place. The one automated hit (YawDragFactor -> +0x0c) remains false: +0x0c holds the integer 2 as a denormal and collided with the float 2.0. Next probe is a RAM-wide search for a unit-distinctive value, not a bigger window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,18 +47,27 @@ fn main() {
|
||||
let Some((_, va)) = pairs.iter().find(|(i, _)| i == id) else { continue };
|
||||
let Some(words) = live.get(va) else { continue };
|
||||
units += 1;
|
||||
let mut numeric = 0usize;
|
||||
let mut hit = 0usize;
|
||||
for key in obj.tokens() {
|
||||
let Some(v) = obj.get_f32(key) else { continue };
|
||||
if !v.is_finite() || v == 0.0 {
|
||||
continue; // zero matches everywhere and says nothing
|
||||
}
|
||||
numeric += 1;
|
||||
let mut found = false;
|
||||
for (off, w) in words {
|
||||
if (*w - v).abs() <= v.abs() * 1e-6 {
|
||||
*votes.entry(key.clone()).or_default().entry(*off).or_default() += 1;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if found {
|
||||
hit += 1;
|
||||
}
|
||||
}
|
||||
eprintln!(" {id}: {numeric} numeric fields set on disc, {hit} found in the dumped window");
|
||||
}
|
||||
println!("{units} units correlated against their live objects\n");
|
||||
println!("{:<28} {:>8} offsets agreeing (votes)", "field", "unique?");
|
||||
for (key, offs) in &votes {
|
||||
|
||||
7182
docs/re/captures/stage02-live-unit-definitions-deep.txt
Normal file
7182
docs/re/captures/stage02-live-unit-definitions-deep.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -140,16 +140,27 @@ consistent with a field the rest default, but a second anchoring unit that sets
|
||||
them to something *different* is what would prove it. `+0x40` is 0.1 on two units
|
||||
and 1 on three, so it is a real per-unit field — just not identified.
|
||||
|
||||
⚠️ **The automated version of this does not work yet.** `examples/live_offsets.rs`
|
||||
correlates every `get_f32(key)` against every dumped word and keeps offsets all
|
||||
units agree on; over five units it produced exactly **one** hit
|
||||
(`YawDragFactor → +0x0c`), and that hit is **wrong** — `+0x0c` holds the integer
|
||||
2 (as a denormal float, `2.8e-45`), which collided with `YawDragFactor = 2.0`.
|
||||
Two causes, both fixable: the IDXD pool's value-before-key interleaving makes
|
||||
`get_f32` unreliable on records that default many fields (the pairing shifts), so
|
||||
most keys yield nothing; and 96 words only reaches `+0x180`, while `RadarRange
|
||||
60000` / `FCSRange 45000` — both set on the Destroyer — appear nowhere in that
|
||||
window, so much of the record lies beyond it.
|
||||
⚠️ **The automated version finds almost nothing, and the reason is not what it
|
||||
first looked like.** `examples/live_offsets.rs` correlates every `get_f32(key)`
|
||||
against every dumped word and keeps offsets all units agree on. Over five units
|
||||
it produced exactly **one** hit, `YawDragFactor → +0x0c`, and that hit is
|
||||
**wrong**: `+0x0c` holds the integer 2 (printed as the denormal `2.8e-45`), which
|
||||
collided with `YawDragFactor = 2.0`. Any float-compare against small integers has
|
||||
that failure mode.
|
||||
|
||||
So the next run dumps **512 words** per object, and the disc side needs a reader
|
||||
that walks the pool with the default-aware rule rather than `get_f32` per key.
|
||||
The first explanation written here — that `get_f32` is unreliable on
|
||||
default-heavy records — was **wrong**, and measuring killed it: `get_f32`
|
||||
resolves **46–57 numeric fields per unit** (Destroyer 46, `e105` Cruiser 57,
|
||||
`f105` Cruiser 49, `e106` Destroyer 51, Acropolis 45). It is the documented,
|
||||
reliable API and it works.
|
||||
|
||||
The real problem is that **the values are not in this object**. Dumping 512 words
|
||||
(2 KB) instead of 96 changes nothing at all: still exactly **4 of ~50** disc
|
||||
values found, for every one of the five units. So the structure at vtable
|
||||
`0x820af844` is not the parsed definition record — it carries the handful of
|
||||
fields above (sizes, HP, a couple of ratios) and the rest of the record lives
|
||||
elsewhere, presumably behind a pointer.
|
||||
|
||||
Next probe, therefore, is not a bigger window: search guest RAM for a value that
|
||||
is distinctive to one unit (e.g. the Acropolis' `HP 25000` = `0x46c35000`) and see
|
||||
what *other* structure holds it, then map that one.
|
||||
|
||||
Reference in New Issue
Block a user