re: placement X/Y are SIGNED, the tail word is time, and the resting pose is max-dwell
Dumping the remaining Arsenal components turned up placements reading as 4294966780 and 4294966856 -- negative as i32 (-516, -440). X and Y are signed; off-screen animation starts are negative, and read as unsigned a reimplementation would draw them four billion pixels off. The raw region then showed the rest of it. The trailing word is a TIME, and a group is an in -> hold -> out animation: prselect_win1 runs t=4:-516 -> 6:-71 -> 7:81 -> 8:127 -> 23:134 -> 24:134 -> 25:127 -> 27:81 -> 31:-71 -> 1:-516. So NEITHER the first nor the last keyframe is where the element sits -- both are off-screen. The resting position is the max-dwell keyframe, (127,155)..(134,155) here, which is where the weapon-list panel actually appears. This corrects my own note from earlier today, which reported "final=" positions. Static elements were unaffected (the pause menu's buttons have identical keyframes) but animated ones were misread. screen_layout.rs now reports the max-dwell pose plus the full timeline, and both captures are regenerated. Also seen while dumping: kind 0x2, and a .sbo child (scrollbar) parented to the list window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,7 +54,8 @@ fn main() {
|
||||
// Placement region: groups of (u32 element index, u32 keyframe count) then
|
||||
// `count` 40-byte keyframes; the X/Y sit 12 bytes into the scale/tint block.
|
||||
let mut pos = 0x20 + count * 60;
|
||||
let mut placements: Vec<Vec<(u32, u32)>> = vec![Vec::new(); count];
|
||||
// X/Y are SIGNED: off-screen animation starts are negative (e.g. -516).
|
||||
let mut placements: Vec<Vec<(i32, i32, u32)>> = vec![Vec::new(); count];
|
||||
for _ in 0..count {
|
||||
if pos + 8 > bytes.len() { break }
|
||||
let idx = be32(&bytes, pos) as usize;
|
||||
@@ -65,7 +66,7 @@ fn main() {
|
||||
for k in 0..frames {
|
||||
let blk = first + k * 40;
|
||||
if blk + 20 > bytes.len() { break }
|
||||
group.push((be32(&bytes, blk + 12), be32(&bytes, blk + 16)));
|
||||
group.push((be32(&bytes, blk + 12) as i32, be32(&bytes, blk + 16) as i32, be32(&bytes, blk + 20)));
|
||||
}
|
||||
placements[idx] = group;
|
||||
pos = first + frames * 40 - 20;
|
||||
@@ -76,10 +77,25 @@ fn main() {
|
||||
for i in 0..count {
|
||||
let (parent, kind, px, py) = meta[i];
|
||||
let p = &placements[i];
|
||||
let shown = match (p.first(), p.last()) {
|
||||
(Some(f), Some(l)) if p.len() > 1 && f != l => format!("{:?} → {:?}", f, l),
|
||||
(Some(f), _) => format!("{:?}", f),
|
||||
_ => "—".into(),
|
||||
// A group is an in → hold → out animation, so neither the first nor the
|
||||
// last keyframe is where the element sits: report the MAX-DWELL one
|
||||
// (longest gap to the next keyframe's time).
|
||||
let shown = if p.is_empty() {
|
||||
"—".into()
|
||||
} else if p.len() == 1 {
|
||||
format!("({},{})", p[0].0, p[0].1)
|
||||
} else {
|
||||
let mut best = (0usize, 0u32);
|
||||
for k in 0..p.len() - 1 {
|
||||
let d = p[k + 1].2.saturating_sub(p[k].2);
|
||||
if d > best.1 { best = (k, d) }
|
||||
}
|
||||
let r = p[best.0];
|
||||
format!(
|
||||
"rest ({},{}) t={}..{} [{}]",
|
||||
r.0, r.1, r.2, p[best.0 + 1].2,
|
||||
p.iter().map(|(x, y, t)| format!("{t}:{x},{y}")).collect::<Vec<_>>().join(" ")
|
||||
)
|
||||
};
|
||||
println!(
|
||||
"{:<3} {:<30} {:>7} {:>8} {:>12} {:>4} {}",
|
||||
|
||||
Reference in New Issue
Block a user