From a73a789bac4c1f436530a7928ff8b7310571a562 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Fri, 17 Apr 2026 21:01:45 -0700 Subject: [PATCH] Widen save-world finance neighborhood window --- README.md | 3 +++ crates/rrt-runtime/src/smp.rs | 46 +++++++++++++++++++++++++---------- docs/README.md | 4 ++- docs/runtime-rehost-plan.md | 4 ++- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 7f17102..7111bf4 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,9 @@ dividend / stock-capital logic can extend one owned market reader instead of ano counter. The next bundled annual-finance reader seam is now rehosted on top of that same market state too, deriving assigned shares, public float, and rounded cached share price from one shared company market reader instead of scattering more finance helpers across the runtime. A checked-in +The fixed-world finance neighborhood itself is now widened to 16 dwords rooted at `[world+0x11]`, +so future issue-`0x38/0x39` closure can build on a broader owned restore-state window rather than +another narrow one-off probe. A checked-in The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we should prefer rehosting the owning source state or the real reader/setter family rather than guessing one more derived leaf field from nearby offsets. A checked-in diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index 7c59646..867d458 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -109,6 +109,8 @@ const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS: [(&str, usize) ("issue_neighbor_candidate_1", 0x31), ("issue_neighbor_candidate_2", 0x35), ]; +const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_ROOT_RELATIVE_OFFSET: usize = 0x11; +const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS: usize = 16; const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET: usize = 0x83; const RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET: usize = 0xc1; const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET: usize = 0x0bbf; @@ -8705,12 +8707,8 @@ fn parse_save_world_finance_neighborhood_probe( continue; } - let dword_candidates = RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS - .iter() - .map(|(label, relative_offset)| { - build_save_dword_candidate(bytes, payload_offset, label, *relative_offset) - }) - .collect::>>()?; + let dword_candidates = + build_save_world_finance_neighborhood_candidates(bytes, payload_offset)?; return Some(SmpSaveWorldFinanceNeighborhoodProbe { profile_family: profile.profile_family.clone(), @@ -8736,6 +8734,24 @@ fn parse_save_world_finance_neighborhood_probe( None } +fn build_save_world_finance_neighborhood_candidates( + bytes: &[u8], + payload_offset: usize, +) -> Option> { + (0..RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS) + .map(|index| { + let relative_offset = + RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_ROOT_RELATIVE_OFFSET + index * 4; + let label = RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS + .iter() + .find(|(_, named_offset)| *named_offset == relative_offset) + .map(|(name, _)| (*name).to_string()) + .unwrap_or_else(|| format!("finance_neighborhood_word_{:02}", index + 1)); + build_save_dword_candidate(bytes, payload_offset, &label, relative_offset) + }) + .collect() +} + fn parse_save_world_economic_tuning_probe( bytes: &[u8], file_extension_hint: Option<&str>, @@ -15431,12 +15447,10 @@ mod tests { let payload_offset = chunk_tag_offset + 4; bytes[chunk_tag_offset..chunk_tag_offset + 4] .copy_from_slice(&RT3_SAVE_WORLD_BLOCK_CHUNK_TAG.to_le_bytes()); - for (index, (_, relative_offset)) in - RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS - .iter() - .enumerate() - { - bytes[payload_offset + *relative_offset..payload_offset + *relative_offset + 4] + for index in 0..RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS { + let relative_offset = + RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_ROOT_RELATIVE_OFFSET + index * 4; + bytes[payload_offset + relative_offset..payload_offset + relative_offset + 4] .copy_from_slice(&((index as u32) + 1).to_le_bytes()); } let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN; @@ -15458,7 +15472,7 @@ mod tests { assert_eq!(probe.payload_offset, payload_offset); assert_eq!( probe.dword_candidates.len(), - RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS.len() + RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS ); assert_eq!( probe.dword_candidates[0].label, @@ -15474,6 +15488,12 @@ mod tests { ); assert_eq!(probe.dword_candidates[9].relative_offset_hex, "0x35"); assert_eq!(probe.dword_candidates[9].value_i32, 10); + assert_eq!(probe.dword_candidates[10].label, "finance_neighborhood_word_11"); + assert_eq!(probe.dword_candidates[10].relative_offset_hex, "0x39"); + assert_eq!(probe.dword_candidates[10].value_i32, 11); + assert_eq!(probe.dword_candidates[15].label, "finance_neighborhood_word_16"); + assert_eq!(probe.dword_candidates[15].relative_offset_hex, "0x4d"); + assert_eq!(probe.dword_candidates[15].value_i32, 16); } #[test] diff --git a/docs/README.md b/docs/README.md index d419752..c2f00c6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -121,7 +121,9 @@ The highest-value next passes are now: seam is now rehosted for the grounded `0x37` lane, and selected-company summaries now expose the unassigned share pool derived from outstanding shares minus chairman-held shares for later annual finance logic; that same owned company market state now also backs a bundled annual-finance - reader seam for assigned shares, public float, and rounded cached share price + reader seam for assigned shares, public float, and rounded cached share price; the fixed-world + finance neighborhood is now widened to 16 dwords rooted at `[world+0x11]` so later issue-family + closure can target a broader owned restore-state window - the project rule on the remaining closure work is now explicit too: when one runtime-facing field is still ambiguous, prefer rehosting the owning source state or real reader/setter family first instead of guessing another derived leaf field from neighboring raw offsets diff --git a/docs/runtime-rehost-plan.md b/docs/runtime-rehost-plan.md index 3bb9ae1..860455a 100644 --- a/docs/runtime-rehost-plan.md +++ b/docs/runtime-rehost-plan.md @@ -209,7 +209,9 @@ chairman-held shares, so later dividend / stock-capital work can extend a shared reader instead of guessing another finance leaf. The same owned company market state now also supports a bundled annual-finance reader seam for assigned shares, public float, and rounded cached share price, which is a better base for later dividend / issue-calendar simulation than -scattered single-field helpers. +scattered single-field helpers. The fixed-world finance neighborhood is now widened to 16 dwords +rooted at `[world+0x11]`, so later issue-`0x38/0x39` closure can build on a broader owned +restore-state window instead of another narrow probe. ## Why This Boundary