Rehost saved world absolute counter state
This commit is contained in:
parent
126a637bc2
commit
2441fe6374
8 changed files with 381 additions and 54 deletions
|
|
@ -44,7 +44,8 @@ company/chairman scalar candidates, including fixed-world chairman slot / role-g
|
|||
explicit company dword candidate windows, richer chairman qword cache views, and derived
|
||||
holdings-at-share-price / cached purchasing-power comparisons. The same fixed `0x32c8` world
|
||||
block is now probed for the grounded issue-`0x37` pair at `[world+0x29/+0x2d]`, one broader
|
||||
fixed-dword finance neighborhood around the absolute-calendar and issue lanes, and the separate
|
||||
fixed-dword finance neighborhood rooted at `[world+0x0d]` that now carries the saved calendar
|
||||
tuple and absolute-counter owner lanes directly, and the separate
|
||||
six-float economic tuning band, but current atlas evidence still keeps that editor-facing
|
||||
tuning family distinct from the governance issue lanes behind investor confidence and prime-rate
|
||||
math. The next shared company-side slice is now rehosted too: save-native company direct records
|
||||
|
|
@ -66,9 +67,11 @@ 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]`,
|
||||
The fixed-world finance neighborhood itself is now widened to 17 dwords rooted at `[world+0x0d]`,
|
||||
so future issue-`0x38/0x39` closure can build on a broader owned restore-state window rather than
|
||||
another narrow one-off probe. The next company-side seam is now bundled too: a shared company
|
||||
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 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
|
||||
the owned annual-finance state instead of leaving that logic spread across summary helpers. The
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ pub struct ExpectedRuntimeSummary {
|
|||
#[serde(default)]
|
||||
pub world_restore_absolute_counter_reconstructible_from_save: Option<bool>,
|
||||
#[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>,
|
||||
#[serde(default)]
|
||||
pub world_restore_absolute_counter_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub world_restore_absolute_counter_mirror_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub world_restore_disable_cargo_economy_special_condition_slot: Option<u8>,
|
||||
#[serde(default)]
|
||||
pub world_restore_disable_cargo_economy_special_condition_reconstructible_from_save:
|
||||
|
|
@ -369,6 +377,38 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
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!(
|
||||
"world_restore_current_calendar_tuple_word_raw_u32 mismatch: expected {value}, got {:?}",
|
||||
actual.world_restore_current_calendar_tuple_word_raw_u32
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = self.world_restore_current_calendar_tuple_word_2_raw_u32 {
|
||||
if actual.world_restore_current_calendar_tuple_word_2_raw_u32 != Some(value) {
|
||||
mismatches.push(format!(
|
||||
"world_restore_current_calendar_tuple_word_2_raw_u32 mismatch: expected {value}, got {:?}",
|
||||
actual.world_restore_current_calendar_tuple_word_2_raw_u32
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = self.world_restore_absolute_counter_raw_u32 {
|
||||
if actual.world_restore_absolute_counter_raw_u32 != Some(value) {
|
||||
mismatches.push(format!(
|
||||
"world_restore_absolute_counter_raw_u32 mismatch: expected {value}, got {:?}",
|
||||
actual.world_restore_absolute_counter_raw_u32
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = self.world_restore_absolute_counter_mirror_raw_u32 {
|
||||
if actual.world_restore_absolute_counter_mirror_raw_u32 != Some(value) {
|
||||
mismatches.push(format!(
|
||||
"world_restore_absolute_counter_mirror_raw_u32 mismatch: expected {value}, got {:?}",
|
||||
actual.world_restore_absolute_counter_mirror_raw_u32
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(slot) = self.world_restore_disable_cargo_economy_special_condition_slot {
|
||||
if actual.world_restore_disable_cargo_economy_special_condition_slot != Some(slot) {
|
||||
mismatches.push(format!(
|
||||
|
|
|
|||
|
|
@ -527,11 +527,18 @@ fn project_save_slice_components(
|
|||
);
|
||||
metadata.insert(
|
||||
"save_slice.selected_year_absolute_counter_source".to_string(),
|
||||
"mode-adjusted-lane-via-0x51d390-0x409e80".to_string(),
|
||||
if save_slice.world_finance_neighborhood_state.is_some() {
|
||||
"save-direct-world-block-absolute-counter".to_string()
|
||||
} else {
|
||||
"mode-adjusted-lane-via-0x51d390-0x409e80".to_string()
|
||||
},
|
||||
);
|
||||
metadata.insert(
|
||||
"save_slice.selected_year_absolute_counter_reconstructible_from_save".to_string(),
|
||||
"false".to_string(),
|
||||
save_slice
|
||||
.world_finance_neighborhood_state
|
||||
.is_some()
|
||||
.to_string(),
|
||||
);
|
||||
metadata.insert(
|
||||
"save_slice.disable_cargo_economy_special_condition_slot".to_string(),
|
||||
|
|
@ -547,8 +554,12 @@ fn project_save_slice_components(
|
|||
);
|
||||
metadata.insert(
|
||||
"save_slice.selected_year_absolute_counter_adjustment_context".to_string(),
|
||||
"editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
|
||||
.to_string(),
|
||||
if save_slice.world_finance_neighborhood_state.is_some() {
|
||||
"save-direct-world-block-0x32c8".to_string()
|
||||
} else {
|
||||
"editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
|
||||
.to_string()
|
||||
},
|
||||
);
|
||||
metadata.insert(
|
||||
"save_slice.mechanism_family".to_string(),
|
||||
|
|
@ -726,8 +737,28 @@ fn project_save_slice_components(
|
|||
campaign_scenario_enabled: Some(profile.profile_byte_0xc5 != 0),
|
||||
sandbox_enabled: Some(profile.profile_byte_0x82 != 0),
|
||||
seed_tuple_written_from_raw_lane: Some(true),
|
||||
absolute_counter_requires_shell_context: Some(true),
|
||||
absolute_counter_reconstructible_from_save: Some(false),
|
||||
absolute_counter_requires_shell_context: Some(
|
||||
save_slice.world_finance_neighborhood_state.is_none(),
|
||||
),
|
||||
absolute_counter_reconstructible_from_save: Some(
|
||||
save_slice.world_finance_neighborhood_state.is_some(),
|
||||
),
|
||||
current_calendar_tuple_word_raw_u32: save_slice
|
||||
.world_finance_neighborhood_state
|
||||
.as_ref()
|
||||
.map(|state| state.current_calendar_tuple_word_raw_u32),
|
||||
current_calendar_tuple_word_2_raw_u32: save_slice
|
||||
.world_finance_neighborhood_state
|
||||
.as_ref()
|
||||
.map(|state| state.current_calendar_tuple_word_2_raw_u32),
|
||||
absolute_counter_raw_u32: save_slice
|
||||
.world_finance_neighborhood_state
|
||||
.as_ref()
|
||||
.map(|state| state.absolute_counter_raw_u32),
|
||||
absolute_counter_mirror_raw_u32: save_slice
|
||||
.world_finance_neighborhood_state
|
||||
.as_ref()
|
||||
.map(|state| state.absolute_counter_mirror_raw_u32),
|
||||
disable_cargo_economy_special_condition_slot: Some(30),
|
||||
disable_cargo_economy_special_condition_reconstructible_from_save: Some(true),
|
||||
disable_cargo_economy_special_condition_write_side_grounded: Some(true),
|
||||
|
|
@ -791,11 +822,19 @@ fn project_save_slice_components(
|
|||
.map(|state| state.lane_value_f32_text.clone())
|
||||
.unwrap_or_default(),
|
||||
absolute_counter_restore_kind: Some(
|
||||
"mode-adjusted-selected-year-lane".to_string(),
|
||||
if save_slice.world_finance_neighborhood_state.is_some() {
|
||||
"save-direct-world-absolute-counter".to_string()
|
||||
} else {
|
||||
"mode-adjusted-selected-year-lane".to_string()
|
||||
},
|
||||
),
|
||||
absolute_counter_adjustment_context: Some(
|
||||
"editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
|
||||
.to_string(),
|
||||
if save_slice.world_finance_neighborhood_state.is_some() {
|
||||
"save-direct-world-block-0x32c8".to_string()
|
||||
} else {
|
||||
"editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
|
||||
.to_string()
|
||||
},
|
||||
),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -5800,7 +5839,45 @@ mod tests {
|
|||
lane_raw_hex: vec!["0x3f400000".to_string(), "0x3be56042".to_string()],
|
||||
lane_value_f32_text: vec!["0.750000".to_string(), "0.007000".to_string()],
|
||||
}),
|
||||
world_finance_neighborhood_state: None,
|
||||
world_finance_neighborhood_state: Some(crate::SmpLoadedWorldFinanceNeighborhoodState {
|
||||
source_kind: "save-fixed-world-block".to_string(),
|
||||
semantic_family: "world-finance-neighborhood".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,
|
||||
current_calendar_tuple_word_2_raw_hex: "0x00000002".to_string(),
|
||||
absolute_counter_raw_u32: 3,
|
||||
absolute_counter_raw_hex: "0x00000003".to_string(),
|
||||
absolute_counter_mirror_raw_u32: 4,
|
||||
absolute_counter_mirror_raw_hex: "0x00000004".to_string(),
|
||||
labels: vec![
|
||||
"current_calendar_tuple_word".to_string(),
|
||||
"current_calendar_tuple_word_2".to_string(),
|
||||
"absolute_calendar_counter".to_string(),
|
||||
"absolute_calendar_counter_mirror".to_string(),
|
||||
],
|
||||
relative_offsets: vec![0x0d, 0x11, 0x15, 0x19],
|
||||
relative_offset_hex: vec![
|
||||
"0xd".to_string(),
|
||||
"0x11".to_string(),
|
||||
"0x15".to_string(),
|
||||
"0x19".to_string(),
|
||||
],
|
||||
raw_u32: vec![1, 2, 3, 4],
|
||||
raw_hex: vec![
|
||||
"0x00000001".to_string(),
|
||||
"0x00000002".to_string(),
|
||||
"0x00000003".to_string(),
|
||||
"0x00000004".to_string(),
|
||||
],
|
||||
value_i32: vec![1, 2, 3, 4],
|
||||
value_f32_text: vec![
|
||||
"0.000000".to_string(),
|
||||
"0.000000".to_string(),
|
||||
"0.000000".to_string(),
|
||||
"0.000000".to_string(),
|
||||
],
|
||||
}),
|
||||
company_roster: None,
|
||||
chairman_profile_table: None,
|
||||
special_conditions_table: Some(crate::SmpLoadedSpecialConditionsTable {
|
||||
|
|
@ -5959,14 +6036,39 @@ mod tests {
|
|||
.state
|
||||
.world_restore
|
||||
.absolute_counter_requires_shell_context,
|
||||
Some(true)
|
||||
Some(false)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_restore
|
||||
.absolute_counter_reconstructible_from_save,
|
||||
Some(false)
|
||||
Some(true)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_restore
|
||||
.current_calendar_tuple_word_raw_u32,
|
||||
Some(1)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_restore
|
||||
.current_calendar_tuple_word_2_raw_u32,
|
||||
Some(2)
|
||||
);
|
||||
assert_eq!(
|
||||
import.state.world_restore.absolute_counter_raw_u32,
|
||||
Some(3)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.world_restore
|
||||
.absolute_counter_mirror_raw_u32,
|
||||
Some(4)
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
|
|
@ -6064,7 +6166,7 @@ mod tests {
|
|||
.world_restore
|
||||
.absolute_counter_restore_kind
|
||||
.as_deref(),
|
||||
Some("mode-adjusted-selected-year-lane")
|
||||
Some("save-direct-world-absolute-counter")
|
||||
);
|
||||
assert_eq!(
|
||||
import
|
||||
|
|
@ -6072,9 +6174,7 @@ mod tests {
|
|||
.world_restore
|
||||
.absolute_counter_adjustment_context
|
||||
.as_deref(),
|
||||
Some(
|
||||
"editor-map-mode,shell-selected-year-adjust-policy-0x9d26-0x9d28,save-special-condition-disable-cargo-economy-slot-30"
|
||||
)
|
||||
Some("save-direct-world-block-0x32c8")
|
||||
);
|
||||
assert_eq!(
|
||||
import.state.save_profile.map_path.as_deref(),
|
||||
|
|
|
|||
|
|
@ -987,6 +987,14 @@ pub struct RuntimeWorldRestoreState {
|
|||
#[serde(default)]
|
||||
pub absolute_counter_reconstructible_from_save: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub current_calendar_tuple_word_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub current_calendar_tuple_word_2_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub absolute_counter_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub absolute_counter_mirror_raw_u32: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub disable_cargo_economy_special_condition_slot: Option<u8>,
|
||||
#[serde(default)]
|
||||
pub disable_cargo_economy_special_condition_reconstructible_from_save: Option<bool>,
|
||||
|
|
@ -1909,6 +1917,10 @@ pub fn runtime_world_issue_state(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn runtime_world_absolute_counter(state: &RuntimeState) -> Option<u32> {
|
||||
state.world_restore.absolute_counter_raw_u32
|
||||
}
|
||||
|
||||
pub fn runtime_company_unassigned_share_pool(state: &RuntimeState, company_id: u32) -> Option<u32> {
|
||||
let outstanding_shares = state
|
||||
.service_state
|
||||
|
|
@ -2570,6 +2582,10 @@ mod tests {
|
|||
seed_tuple_written_from_raw_lane: Some(true),
|
||||
absolute_counter_requires_shell_context: Some(true),
|
||||
absolute_counter_reconstructible_from_save: Some(false),
|
||||
current_calendar_tuple_word_raw_u32: None,
|
||||
current_calendar_tuple_word_2_raw_u32: None,
|
||||
absolute_counter_raw_u32: None,
|
||||
absolute_counter_mirror_raw_u32: None,
|
||||
disable_cargo_economy_special_condition_slot: Some(30),
|
||||
disable_cargo_economy_special_condition_reconstructible_from_save: Some(true),
|
||||
disable_cargo_economy_special_condition_write_side_grounded: Some(true),
|
||||
|
|
@ -4078,6 +4094,62 @@ mod tests {
|
|||
assert_eq!(issue.multiplier_raw_u32, 0x3d75c28f);
|
||||
assert_eq!(issue.multiplier_value_f32_text, "0.060000");
|
||||
assert_eq!(runtime_world_issue_state(&state, 0x39), None);
|
||||
assert_eq!(runtime_world_absolute_counter(&state), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_grounded_world_absolute_counter_from_runtime_restore_state() {
|
||||
let state = RuntimeState {
|
||||
calendar: CalendarPoint {
|
||||
year: 1830,
|
||||
month_slot: 0,
|
||||
phase_slot: 0,
|
||||
tick_slot: 0,
|
||||
},
|
||||
world_flags: BTreeMap::new(),
|
||||
save_profile: RuntimeSaveProfileState::default(),
|
||||
world_restore: RuntimeWorldRestoreState {
|
||||
absolute_counter_raw_u32: Some(5),
|
||||
absolute_counter_mirror_raw_u32: Some(5),
|
||||
current_calendar_tuple_word_raw_u32: Some(0x0108_0210),
|
||||
current_calendar_tuple_word_2_raw_u32: Some(0x35e6_3160),
|
||||
..RuntimeWorldRestoreState::default()
|
||||
},
|
||||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
chairman_profiles: Vec::new(),
|
||||
selected_chairman_profile_id: None,
|
||||
trains: Vec::new(),
|
||||
locomotive_catalog: Vec::new(),
|
||||
cargo_catalog: Vec::new(),
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
company_territory_access: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
event_runtime_records: Vec::new(),
|
||||
candidate_availability: BTreeMap::new(),
|
||||
named_locomotive_availability: BTreeMap::new(),
|
||||
named_locomotive_cost: BTreeMap::new(),
|
||||
all_cargo_price_override: None,
|
||||
named_cargo_price_overrides: BTreeMap::new(),
|
||||
all_cargo_production_override: None,
|
||||
factory_cargo_production_override: None,
|
||||
farm_mine_cargo_production_override: None,
|
||||
named_cargo_production_overrides: BTreeMap::new(),
|
||||
cargo_production_overrides: BTreeMap::new(),
|
||||
world_runtime_variables: BTreeMap::new(),
|
||||
company_runtime_variables: BTreeMap::new(),
|
||||
player_runtime_variables: BTreeMap::new(),
|
||||
territory_runtime_variables: BTreeMap::new(),
|
||||
world_scalar_overrides: BTreeMap::new(),
|
||||
special_conditions: BTreeMap::new(),
|
||||
service_state: RuntimeServiceState::default(),
|
||||
};
|
||||
|
||||
assert_eq!(runtime_world_absolute_counter(&state), Some(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -97,10 +97,27 @@ const RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET: usize = 0x1d;
|
|||
const RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET: usize = 0x21;
|
||||
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET: usize = 0x25;
|
||||
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET: usize = 0x29;
|
||||
const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS: [(&str, usize); 10] = [
|
||||
("absolute_calendar_counter_candidate_0", 0x11),
|
||||
("absolute_calendar_counter_candidate_1", 0x15),
|
||||
("absolute_calendar_counter_candidate_2", 0x19),
|
||||
const RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET: usize = 0x0d;
|
||||
const RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_2_RELATIVE_OFFSET: usize = 0x11;
|
||||
const RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_RELATIVE_OFFSET: usize = 0x15;
|
||||
const RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_MIRROR_RELATIVE_OFFSET: usize = 0x19;
|
||||
const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS: [(&str, usize); 11] = [
|
||||
(
|
||||
"current_calendar_tuple_word",
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET,
|
||||
),
|
||||
(
|
||||
"current_calendar_tuple_word_2",
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_2_RELATIVE_OFFSET,
|
||||
),
|
||||
(
|
||||
"absolute_calendar_counter",
|
||||
RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_RELATIVE_OFFSET,
|
||||
),
|
||||
(
|
||||
"absolute_calendar_counter_mirror",
|
||||
RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_MIRROR_RELATIVE_OFFSET,
|
||||
),
|
||||
("selection_context_candidate_0", 0x1d),
|
||||
("selection_context_candidate_1", 0x21),
|
||||
("issue_0x37_multiplier", 0x25),
|
||||
|
|
@ -109,8 +126,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_FINANCE_NEIGHBORHOOD_ROOT_RELATIVE_OFFSET: usize = 0x0d;
|
||||
const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS: usize = 17;
|
||||
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;
|
||||
|
|
@ -1535,6 +1552,10 @@ pub struct SmpSaveWorldFinanceNeighborhoodProbe {
|
|||
pub payload_offset: usize,
|
||||
pub payload_len: usize,
|
||||
pub payload_len_hex: String,
|
||||
pub current_calendar_tuple_word_lane: SmpSaveDwordCandidate,
|
||||
pub current_calendar_tuple_word_2_lane: SmpSaveDwordCandidate,
|
||||
pub absolute_counter_lane: SmpSaveDwordCandidate,
|
||||
pub absolute_counter_mirror_lane: SmpSaveDwordCandidate,
|
||||
pub dword_candidates: Vec<SmpSaveDwordCandidate>,
|
||||
pub evidence: Vec<String>,
|
||||
}
|
||||
|
|
@ -2199,6 +2220,14 @@ pub struct SmpLoadedWorldEconomicTuningState {
|
|||
pub struct SmpLoadedWorldFinanceNeighborhoodState {
|
||||
pub source_kind: String,
|
||||
pub semantic_family: 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,
|
||||
pub current_calendar_tuple_word_2_raw_hex: String,
|
||||
pub absolute_counter_raw_u32: u32,
|
||||
pub absolute_counter_raw_hex: String,
|
||||
pub absolute_counter_mirror_raw_u32: u32,
|
||||
pub absolute_counter_mirror_raw_hex: String,
|
||||
pub labels: Vec<String>,
|
||||
pub relative_offsets: Vec<usize>,
|
||||
pub relative_offset_hex: Vec<String>,
|
||||
|
|
@ -3412,6 +3441,20 @@ fn derive_loaded_world_finance_neighborhood_state_from_probe(
|
|||
SmpLoadedWorldFinanceNeighborhoodState {
|
||||
source_kind: probe.source_kind.clone(),
|
||||
semantic_family: probe.semantic_family.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
|
||||
.raw_u32_hex
|
||||
.clone(),
|
||||
current_calendar_tuple_word_2_raw_u32: probe.current_calendar_tuple_word_2_lane.raw_u32,
|
||||
current_calendar_tuple_word_2_raw_hex: probe
|
||||
.current_calendar_tuple_word_2_lane
|
||||
.raw_u32_hex
|
||||
.clone(),
|
||||
absolute_counter_raw_u32: probe.absolute_counter_lane.raw_u32,
|
||||
absolute_counter_raw_hex: probe.absolute_counter_lane.raw_u32_hex.clone(),
|
||||
absolute_counter_mirror_raw_u32: probe.absolute_counter_mirror_lane.raw_u32,
|
||||
absolute_counter_mirror_raw_hex: probe.absolute_counter_mirror_lane.raw_u32_hex.clone(),
|
||||
labels: probe
|
||||
.dword_candidates
|
||||
.iter()
|
||||
|
|
@ -8808,6 +8851,30 @@ fn parse_save_world_finance_neighborhood_probe(
|
|||
continue;
|
||||
}
|
||||
|
||||
let current_calendar_tuple_word_lane = build_save_dword_candidate(
|
||||
bytes,
|
||||
payload_offset,
|
||||
"current_calendar_tuple_word",
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET,
|
||||
)?;
|
||||
let current_calendar_tuple_word_2_lane = build_save_dword_candidate(
|
||||
bytes,
|
||||
payload_offset,
|
||||
"current_calendar_tuple_word_2",
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_2_RELATIVE_OFFSET,
|
||||
)?;
|
||||
let absolute_counter_lane = build_save_dword_candidate(
|
||||
bytes,
|
||||
payload_offset,
|
||||
"absolute_calendar_counter",
|
||||
RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_RELATIVE_OFFSET,
|
||||
)?;
|
||||
let absolute_counter_mirror_lane = build_save_dword_candidate(
|
||||
bytes,
|
||||
payload_offset,
|
||||
"absolute_calendar_counter_mirror",
|
||||
RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_MIRROR_RELATIVE_OFFSET,
|
||||
)?;
|
||||
let dword_candidates =
|
||||
build_save_world_finance_neighborhood_candidates(bytes, payload_offset)?;
|
||||
|
||||
|
|
@ -8819,6 +8886,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),
|
||||
current_calendar_tuple_word_lane,
|
||||
current_calendar_tuple_word_2_lane,
|
||||
absolute_counter_lane,
|
||||
absolute_counter_mirror_lane,
|
||||
dword_candidates,
|
||||
evidence: vec![
|
||||
format!(
|
||||
|
|
@ -8827,7 +8898,13 @@ fn parse_save_world_finance_neighborhood_probe(
|
|||
format!(
|
||||
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
|
||||
),
|
||||
"finance-neighborhood candidates cover the fixed dword strip around the grounded world absolute-calendar, selection-context, and issue-0x37 lanes so broader issue-state closure can build on one rehosted owner surface.".to_string(),
|
||||
format!(
|
||||
"payload +0x{:x}/+0x{:x}/+0x{:x} carry the saved world calendar tuple and absolute counter lanes that later company stock-issue cooldown readers compare against",
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_RELATIVE_OFFSET,
|
||||
RT3_SAVE_WORLD_BLOCK_CURRENT_CALENDAR_TUPLE_WORD_2_RELATIVE_OFFSET,
|
||||
RT3_SAVE_WORLD_BLOCK_ABSOLUTE_COUNTER_RELATIVE_OFFSET
|
||||
),
|
||||
"finance-neighborhood candidates cover the fixed dword strip around the grounded world calendar tuple, absolute-counter, selection-context, and issue-0x37 lanes so broader finance reader closure can build on one rehosted owner surface.".to_string(),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
|
@ -15575,32 +15652,31 @@ mod tests {
|
|||
probe.dword_candidates.len(),
|
||||
RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_WINDOW_LEN_DWORDS
|
||||
);
|
||||
assert_eq!(
|
||||
probe.dword_candidates[0].label,
|
||||
"absolute_calendar_counter_candidate_0"
|
||||
);
|
||||
assert_eq!(probe.dword_candidates[0].relative_offset_hex, "0x11");
|
||||
assert_eq!(probe.current_calendar_tuple_word_lane.relative_offset_hex, "0xd");
|
||||
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);
|
||||
assert_eq!(probe.absolute_counter_lane.relative_offset_hex, "0x15");
|
||||
assert_eq!(probe.absolute_counter_lane.value_i32, 3);
|
||||
assert_eq!(probe.absolute_counter_mirror_lane.relative_offset_hex, "0x19");
|
||||
assert_eq!(probe.absolute_counter_mirror_lane.value_i32, 4);
|
||||
assert_eq!(probe.dword_candidates[0].label, "current_calendar_tuple_word");
|
||||
assert_eq!(probe.dword_candidates[0].relative_offset_hex, "0xd");
|
||||
assert_eq!(probe.dword_candidates[0].value_i32, 1);
|
||||
assert_eq!(probe.dword_candidates[5].label, "issue_0x37_multiplier");
|
||||
assert_eq!(probe.dword_candidates[5].relative_offset_hex, "0x25");
|
||||
assert_eq!(
|
||||
probe.dword_candidates[9].label,
|
||||
"issue_neighbor_candidate_2"
|
||||
);
|
||||
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[6].label, "issue_0x37_multiplier");
|
||||
assert_eq!(probe.dword_candidates[6].relative_offset_hex, "0x25");
|
||||
assert_eq!(probe.dword_candidates[10].label, "issue_neighbor_candidate_2");
|
||||
assert_eq!(probe.dword_candidates[10].relative_offset_hex, "0x35");
|
||||
assert_eq!(probe.dword_candidates[10].value_i32, 11);
|
||||
assert_eq!(probe.dword_candidates[11].label, "finance_neighborhood_word_12");
|
||||
assert_eq!(probe.dword_candidates[11].relative_offset_hex, "0x39");
|
||||
assert_eq!(probe.dword_candidates[11].value_i32, 12);
|
||||
assert_eq!(
|
||||
probe.dword_candidates[15].label,
|
||||
"finance_neighborhood_word_16"
|
||||
probe.dword_candidates[16].label,
|
||||
"finance_neighborhood_word_17"
|
||||
);
|
||||
assert_eq!(probe.dword_candidates[15].relative_offset_hex, "0x4d");
|
||||
assert_eq!(probe.dword_candidates[15].value_i32, 16);
|
||||
assert_eq!(probe.dword_candidates[16].relative_offset_hex, "0x4d");
|
||||
assert_eq!(probe.dword_candidates[16].value_i32, 17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ 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_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>,
|
||||
pub world_restore_absolute_counter_mirror_raw_u32: Option<u32>,
|
||||
pub world_restore_disable_cargo_economy_special_condition_slot: Option<u8>,
|
||||
pub world_restore_disable_cargo_economy_special_condition_reconstructible_from_save:
|
||||
Option<bool>,
|
||||
|
|
@ -178,6 +182,18 @@ impl RuntimeSummary {
|
|||
world_restore_absolute_counter_reconstructible_from_save: state
|
||||
.world_restore
|
||||
.absolute_counter_reconstructible_from_save,
|
||||
world_restore_current_calendar_tuple_word_raw_u32: state
|
||||
.world_restore
|
||||
.current_calendar_tuple_word_raw_u32,
|
||||
world_restore_current_calendar_tuple_word_2_raw_u32: state
|
||||
.world_restore
|
||||
.current_calendar_tuple_word_2_raw_u32,
|
||||
world_restore_absolute_counter_raw_u32: state
|
||||
.world_restore
|
||||
.absolute_counter_raw_u32,
|
||||
world_restore_absolute_counter_mirror_raw_u32: state
|
||||
.world_restore
|
||||
.absolute_counter_mirror_raw_u32,
|
||||
world_restore_disable_cargo_economy_special_condition_slot: state
|
||||
.world_restore
|
||||
.disable_cargo_economy_special_condition_slot,
|
||||
|
|
@ -1142,6 +1158,10 @@ mod tests {
|
|||
world_flags: BTreeMap::new(),
|
||||
save_profile: RuntimeSaveProfileState::default(),
|
||||
world_restore: RuntimeWorldRestoreState {
|
||||
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),
|
||||
absolute_counter_mirror_raw_u32: Some(5),
|
||||
issue_37_value: Some(3),
|
||||
issue_37_multiplier_raw_u32: Some(0x3d75c28f),
|
||||
issue_37_multiplier_value_f32_text: Some("0.06".to_string()),
|
||||
|
|
@ -1206,6 +1226,19 @@ mod tests {
|
|||
|
||||
let summary = RuntimeSummary::from_state(&state);
|
||||
|
||||
assert_eq!(
|
||||
summary.world_restore_current_calendar_tuple_word_raw_u32,
|
||||
Some(0x0108_0210)
|
||||
);
|
||||
assert_eq!(
|
||||
summary.world_restore_current_calendar_tuple_word_2_raw_u32,
|
||||
Some(0x35e6_3160)
|
||||
);
|
||||
assert_eq!(summary.world_restore_absolute_counter_raw_u32, Some(5));
|
||||
assert_eq!(
|
||||
summary.world_restore_absolute_counter_mirror_raw_u32,
|
||||
Some(5)
|
||||
);
|
||||
assert_eq!(summary.world_restore_issue_37_value, Some(3));
|
||||
assert_eq!(
|
||||
summary.world_restore_issue_37_multiplier_raw_u32,
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ The highest-value next passes are now:
|
|||
`runtime inspect-save-company-chairman <save.gms>` now dumps those remaining raw record
|
||||
candidates directly from the rehosted parser, including fixed-world chairman slot / role-gate
|
||||
context, the grounded fixed-world issue-`0x37` pair, the fixed-dword world finance
|
||||
neighborhood around the absolute-calendar and issue lanes, the separate six-float economic
|
||||
neighborhood rooted at `[world+0x0d]` with the saved calendar tuple and absolute counter, the separate six-float economic
|
||||
tuning band, derived holdings-at-share-price and cached purchasing-power totals,
|
||||
context, company dword candidate windows, and richer chairman qword cache views; the current
|
||||
rehosted company-side owner state now also includes a typed market/cache map carrying saved
|
||||
|
|
@ -122,8 +122,9 @@ The highest-value next passes are now:
|
|||
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; 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 same annual-finance state now also
|
||||
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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -209,9 +209,11 @@ 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. 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. The same owned company annual-finance state
|
||||
scattered single-field helpers. The fixed-world finance neighborhood is now widened to 17 dwords
|
||||
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
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue