Rehost save-world partial-year weighting inputs

This commit is contained in:
Jan Petykiewicz 2026-04-17 22:05:29 -07:00
commit b81b67d2b3
8 changed files with 119 additions and 2 deletions

View file

@ -71,6 +71,9 @@ The fixed-world finance neighborhood itself is now widened to 17 dwords rooted a
so future issue-`0x38/0x39` closure can build on a broader owned restore-state window rather than
another narrow one-off probe; that same owner surface now also carries the saved absolute counter
as first-class runtime restore state instead of leaving it on “requires shell context” metadata.
The same save-world owner surface now also carries the packed year word and partial-year progress
lane behind the annual-finance recent-history weighting path, so later finance readers can attach
to real world-calendar state instead of candidate bytes.
The next company-side seam is now bundled too: a shared company
market reader now exposes outstanding shares, assigned shares, public float, rounded cached share
price, salary lanes, bonus amount, and the full two-word current/prior issue-calendar tuples from

View file

@ -35,6 +35,10 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub world_restore_absolute_counter_reconstructible_from_save: Option<bool>,
#[serde(default)]
pub world_restore_packed_year_word_raw_u16: Option<u16>,
#[serde(default)]
pub world_restore_partial_year_progress_raw_u8: Option<u8>,
#[serde(default)]
pub world_restore_current_calendar_tuple_word_raw_u32: Option<u32>,
#[serde(default)]
pub world_restore_current_calendar_tuple_word_2_raw_u32: Option<u32>,
@ -130,6 +134,8 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub selected_company_years_since_last_dividend: Option<u32>,
#[serde(default)]
pub selected_company_current_partial_year_weight_numerator: Option<i64>,
#[serde(default)]
pub selected_company_chairman_bonus_year: Option<u32>,
#[serde(default)]
pub selected_company_chairman_bonus_amount: Option<i32>,
@ -377,6 +383,22 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(value) = self.world_restore_packed_year_word_raw_u16 {
if actual.world_restore_packed_year_word_raw_u16 != Some(value) {
mismatches.push(format!(
"world_restore_packed_year_word_raw_u16 mismatch: expected {value}, got {:?}",
actual.world_restore_packed_year_word_raw_u16
));
}
}
if let Some(value) = self.world_restore_partial_year_progress_raw_u8 {
if actual.world_restore_partial_year_progress_raw_u8 != Some(value) {
mismatches.push(format!(
"world_restore_partial_year_progress_raw_u8 mismatch: expected {value}, got {:?}",
actual.world_restore_partial_year_progress_raw_u8
));
}
}
if let Some(value) = self.world_restore_current_calendar_tuple_word_raw_u32 {
if actual.world_restore_current_calendar_tuple_word_raw_u32 != Some(value) {
mismatches.push(format!(
@ -783,6 +805,14 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(value) = self.selected_company_current_partial_year_weight_numerator {
if actual.selected_company_current_partial_year_weight_numerator != Some(value) {
mismatches.push(format!(
"selected_company_current_partial_year_weight_numerator mismatch: expected {value}, got {:?}",
actual.selected_company_current_partial_year_weight_numerator
));
}
}
if let Some(value) = self.selected_company_chairman_bonus_year {
if actual.selected_company_chairman_bonus_year != Some(value) {
mismatches.push(format!(

View file

@ -743,6 +743,14 @@ fn project_save_slice_components(
absolute_counter_reconstructible_from_save: Some(
save_slice.world_finance_neighborhood_state.is_some(),
),
packed_year_word_raw_u16: save_slice
.world_finance_neighborhood_state
.as_ref()
.map(|state| state.packed_year_word_raw_u16),
partial_year_progress_raw_u8: save_slice
.world_finance_neighborhood_state
.as_ref()
.map(|state| state.partial_year_progress_raw_u8),
current_calendar_tuple_word_raw_u32: save_slice
.world_finance_neighborhood_state
.as_ref()
@ -5842,6 +5850,10 @@ mod tests {
world_finance_neighborhood_state: Some(crate::SmpLoadedWorldFinanceNeighborhoodState {
source_kind: "save-fixed-world-block".to_string(),
semantic_family: "world-finance-neighborhood".to_string(),
packed_year_word_raw_u16: 0x0201,
packed_year_word_raw_hex: "0x0201".to_string(),
partial_year_progress_raw_u8: 3,
partial_year_progress_raw_hex: "0x03".to_string(),
current_calendar_tuple_word_raw_u32: 1,
current_calendar_tuple_word_raw_hex: "0x00000001".to_string(),
current_calendar_tuple_word_2_raw_u32: 2,
@ -6045,6 +6057,14 @@ mod tests {
.absolute_counter_reconstructible_from_save,
Some(true)
);
assert_eq!(
import.state.world_restore.packed_year_word_raw_u16,
Some(0x0201)
);
assert_eq!(
import.state.world_restore.partial_year_progress_raw_u8,
Some(3)
);
assert_eq!(
import
.state

View file

@ -128,6 +128,8 @@ pub struct RuntimeCompanyAnnualFinanceState {
pub years_since_last_bankruptcy: Option<u32>,
#[serde(default)]
pub years_since_last_dividend: Option<u32>,
#[serde(default)]
pub current_partial_year_weight_numerator: Option<i64>,
pub current_issue_calendar_word: u32,
#[serde(default)]
pub current_issue_calendar_word_2: u32,
@ -989,6 +991,10 @@ pub struct RuntimeWorldRestoreState {
#[serde(default)]
pub current_calendar_tuple_word_raw_u32: Option<u32>,
#[serde(default)]
pub packed_year_word_raw_u16: Option<u16>,
#[serde(default)]
pub partial_year_progress_raw_u8: Option<u8>,
#[serde(default)]
pub current_calendar_tuple_word_2_raw_u32: Option<u32>,
#[serde(default)]
pub absolute_counter_raw_u32: Option<u32>,
@ -1921,6 +1927,10 @@ pub fn runtime_world_absolute_counter(state: &RuntimeState) -> Option<u32> {
state.world_restore.absolute_counter_raw_u32
}
pub fn runtime_world_partial_year_weight_numerator(state: &RuntimeState) -> Option<i64> {
Some(i64::from(state.world_restore.partial_year_progress_raw_u8?) * 5 - 5)
}
pub fn runtime_company_unassigned_share_pool(state: &RuntimeState, company_id: u32) -> Option<u32> {
let outstanding_shares = state
.service_state
@ -1976,6 +1986,7 @@ pub fn runtime_company_annual_finance_state(
years_since_founding,
years_since_last_bankruptcy,
years_since_last_dividend,
current_partial_year_weight_numerator: runtime_world_partial_year_weight_numerator(state),
current_issue_calendar_word: market_state.current_issue_calendar_word,
current_issue_calendar_word_2: market_state.current_issue_calendar_word_2,
prior_issue_calendar_word: market_state.prior_issue_calendar_word,
@ -2582,6 +2593,8 @@ mod tests {
seed_tuple_written_from_raw_lane: Some(true),
absolute_counter_requires_shell_context: Some(true),
absolute_counter_reconstructible_from_save: Some(false),
packed_year_word_raw_u16: None,
partial_year_progress_raw_u8: None,
current_calendar_tuple_word_raw_u32: None,
current_calendar_tuple_word_2_raw_u32: None,
absolute_counter_raw_u32: None,
@ -4111,6 +4124,8 @@ mod tests {
world_restore: RuntimeWorldRestoreState {
absolute_counter_raw_u32: Some(5),
absolute_counter_mirror_raw_u32: Some(5),
packed_year_word_raw_u16: Some(0x0210),
partial_year_progress_raw_u8: Some(8),
current_calendar_tuple_word_raw_u32: Some(0x0108_0210),
current_calendar_tuple_word_2_raw_u32: Some(0x35e6_3160),
..RuntimeWorldRestoreState::default()
@ -4150,6 +4165,7 @@ mod tests {
};
assert_eq!(runtime_world_absolute_counter(&state), Some(5));
assert_eq!(runtime_world_partial_year_weight_numerator(&state), Some(35));
}
#[test]
@ -4386,6 +4402,7 @@ mod tests {
years_since_founding: None,
years_since_last_bankruptcy: None,
years_since_last_dividend: None,
current_partial_year_weight_numerator: None,
current_issue_calendar_word: 5,
current_issue_calendar_word_2: 6,
prior_issue_calendar_word: 4,

View file

@ -1552,6 +1552,10 @@ pub struct SmpSaveWorldFinanceNeighborhoodProbe {
pub payload_offset: usize,
pub payload_len: usize,
pub payload_len_hex: String,
pub packed_year_word_raw_u16: u16,
pub packed_year_word_raw_hex: String,
pub partial_year_progress_raw_u8: u8,
pub partial_year_progress_raw_hex: String,
pub current_calendar_tuple_word_lane: SmpSaveDwordCandidate,
pub current_calendar_tuple_word_2_lane: SmpSaveDwordCandidate,
pub absolute_counter_lane: SmpSaveDwordCandidate,
@ -2220,6 +2224,10 @@ pub struct SmpLoadedWorldEconomicTuningState {
pub struct SmpLoadedWorldFinanceNeighborhoodState {
pub source_kind: String,
pub semantic_family: String,
pub packed_year_word_raw_u16: u16,
pub packed_year_word_raw_hex: String,
pub partial_year_progress_raw_u8: u8,
pub partial_year_progress_raw_hex: String,
pub current_calendar_tuple_word_raw_u32: u32,
pub current_calendar_tuple_word_raw_hex: String,
pub current_calendar_tuple_word_2_raw_u32: u32,
@ -3441,6 +3449,10 @@ fn derive_loaded_world_finance_neighborhood_state_from_probe(
SmpLoadedWorldFinanceNeighborhoodState {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
packed_year_word_raw_u16: probe.packed_year_word_raw_u16,
packed_year_word_raw_hex: probe.packed_year_word_raw_hex.clone(),
partial_year_progress_raw_u8: probe.partial_year_progress_raw_u8,
partial_year_progress_raw_hex: probe.partial_year_progress_raw_hex.clone(),
current_calendar_tuple_word_raw_u32: probe.current_calendar_tuple_word_lane.raw_u32,
current_calendar_tuple_word_raw_hex: probe
.current_calendar_tuple_word_lane
@ -8857,6 +8869,14 @@ fn parse_save_world_finance_neighborhood_probe(
"current_calendar_tuple_word",
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET,
)?;
let packed_year_word_raw_u16 = read_u16_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET,
)?;
let partial_year_progress_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET + 2,
)?;
let current_calendar_tuple_word_2_lane = build_save_dword_candidate(
bytes,
payload_offset,
@ -8886,6 +8906,10 @@ fn parse_save_world_finance_neighborhood_probe(
payload_offset,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
packed_year_word_raw_u16,
packed_year_word_raw_hex: format!("0x{packed_year_word_raw_u16:04x}"),
partial_year_progress_raw_u8,
partial_year_progress_raw_hex: format!("0x{partial_year_progress_raw_u8:02x}"),
current_calendar_tuple_word_lane,
current_calendar_tuple_word_2_lane,
absolute_counter_lane,
@ -15653,6 +15677,10 @@ mod tests {
RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS
);
assert_eq!(probe.current_calendar_tuple_word_lane.relative_offset_hex, "0xd");
assert_eq!(probe.packed_year_word_raw_u16, 1);
assert_eq!(probe.packed_year_word_raw_hex, "0x0001");
assert_eq!(probe.partial_year_progress_raw_u8, 0);
assert_eq!(probe.partial_year_progress_raw_hex, "0x00");
assert_eq!(probe.current_calendar_tuple_word_lane.value_i32, 1);
assert_eq!(probe.current_calendar_tuple_word_2_lane.relative_offset_hex, "0x11");
assert_eq!(probe.current_calendar_tuple_word_2_lane.value_i32, 2);

View file

@ -21,6 +21,8 @@ pub struct RuntimeSummary {
pub world_restore_seed_tuple_written_from_raw_lane: Option<bool>,
pub world_restore_absolute_counter_requires_shell_context: Option<bool>,
pub world_restore_absolute_counter_reconstructible_from_save: Option<bool>,
pub world_restore_packed_year_word_raw_u16: Option<u16>,
pub world_restore_partial_year_progress_raw_u8: Option<u8>,
pub world_restore_current_calendar_tuple_word_raw_u32: Option<u32>,
pub world_restore_current_calendar_tuple_word_2_raw_u32: Option<u32>,
pub world_restore_absolute_counter_raw_u32: Option<u32>,
@ -69,6 +71,7 @@ pub struct RuntimeSummary {
pub selected_company_years_since_founding: Option<u32>,
pub selected_company_years_since_last_bankruptcy: Option<u32>,
pub selected_company_years_since_last_dividend: Option<u32>,
pub selected_company_current_partial_year_weight_numerator: Option<i64>,
pub selected_company_chairman_bonus_year: Option<u32>,
pub selected_company_chairman_bonus_amount: Option<i32>,
pub player_count: usize,
@ -182,6 +185,12 @@ impl RuntimeSummary {
world_restore_absolute_counter_reconstructible_from_save: state
.world_restore
.absolute_counter_reconstructible_from_save,
world_restore_packed_year_word_raw_u16: state
.world_restore
.packed_year_word_raw_u16,
world_restore_partial_year_progress_raw_u8: state
.world_restore
.partial_year_progress_raw_u8,
world_restore_current_calendar_tuple_word_raw_u32: state
.world_restore
.current_calendar_tuple_word_raw_u32,
@ -319,6 +328,9 @@ impl RuntimeSummary {
selected_company_years_since_last_dividend: selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.years_since_last_dividend),
selected_company_current_partial_year_weight_numerator: selected_company_annual_finance_state
.as_ref()
.and_then(|finance_state| finance_state.current_partial_year_weight_numerator),
selected_company_chairman_bonus_year: selected_company_market_state
.map(|market_state| market_state.chairman_bonus_year)
.filter(|year| *year != 0),
@ -1158,6 +1170,8 @@ mod tests {
world_flags: BTreeMap::new(),
save_profile: RuntimeSaveProfileState::default(),
world_restore: RuntimeWorldRestoreState {
packed_year_word_raw_u16: Some(0x0201),
partial_year_progress_raw_u8: Some(3),
current_calendar_tuple_word_raw_u32: Some(0x0108_0210),
current_calendar_tuple_word_2_raw_u32: Some(0x35e6_3160),
absolute_counter_raw_u32: Some(5),
@ -1226,6 +1240,8 @@ mod tests {
let summary = RuntimeSummary::from_state(&state);
assert_eq!(summary.world_restore_packed_year_word_raw_u16, Some(0x0201));
assert_eq!(summary.world_restore_partial_year_progress_raw_u8, Some(3));
assert_eq!(
summary.world_restore_current_calendar_tuple_word_raw_u32,
Some(0x0108_0210)

View file

@ -124,7 +124,9 @@ The highest-value next passes are now:
reader seam for assigned shares, public float, and rounded cached share price; the fixed-world
finance neighborhood is now widened to 17 dwords rooted at `[world+0x0d]` so later issue-family
closure can target a broader owned restore-state window, and the saved absolute counter now
flows through normal runtime restore state instead of staying on shell-context metadata; the same annual-finance state now also
flows through normal runtime restore state instead of staying on shell-context metadata; that
same world owner surface now also carries the packed year word and partial-year progress lane
behind annual-finance recent-history weighting; the same annual-finance state now also
feeds a shared company market reader for stock-capital, salary, bonus, and the full two-word
current/prior issue-calendar tuples, and now derives elapsed years since founding, last dividend,
and last bankruptcy for later annual finance-policy rehosting; live bond-slot count now travels through that same owned annual-finance

View file

@ -213,7 +213,8 @@ scattered single-field helpers. The fixed-world finance neighborhood is now wide
rooted at `[world+0x0d]`, so later issue-`0x38/0x39` closure can build on a broader owned
restore-state window instead of another narrow probe; that same owner surface now also carries
the saved world absolute counter as first-class runtime restore state instead of shell-context
metadata. The same owned company annual-finance state
metadata, plus the packed year word and partial-year progress lane that feed the annual-finance
recent-history weighting path. The same owned company annual-finance state
now also drives a shared company market reader seam for stock-capital, salary, bonus, and the full
two-word current/prior issue-calendar tuples, which is a better base for shellless finance
simulation than summary-only helpers. That same owned annual-finance state now also derives elapsed