diff --git a/crates/rrt-cli/src/main.rs b/crates/rrt-cli/src/main.rs index c02d71b..e5a9142 100644 --- a/crates/rrt-cli/src/main.rs +++ b/crates/rrt-cli/src/main.rs @@ -5783,6 +5783,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, diff --git a/crates/rrt-runtime/src/import.rs b/crates/rrt-runtime/src/import.rs index 2e72180..31f5c95 100644 --- a/crates/rrt-runtime/src/import.rs +++ b/crates/rrt-runtime/src/import.rs @@ -54,7 +54,7 @@ pub struct RuntimeSaveSliceDocumentSource { pub notes: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct RuntimeSaveSliceDocument { pub format_version: u32, pub save_slice_id: String, @@ -1500,6 +1500,53 @@ fn project_save_slice_components( .to_string(), ); } + if let Some(collection) = &save_slice.region_collection { + metadata.insert( + "save_slice.region_collection_source_kind".to_string(), + collection.source_kind.clone(), + ); + metadata.insert( + "save_slice.region_collection_semantic_family".to_string(), + collection.semantic_family.clone(), + ); + metadata.insert( + "save_slice.region_collection_entry_count".to_string(), + collection.observed_entry_count.to_string(), + ); + metadata.insert( + "save_slice.region_collection_profile_entry_count".to_string(), + collection + .entries + .iter() + .map(|entry| { + entry + .profile_collection + .as_ref() + .map(|collection| collection.entries.len()) + .unwrap_or_default() + }) + .sum::() + .to_string(), + ); + metadata.insert( + "save_slice.region_collection_nonzero_prefix_count".to_string(), + collection + .entries + .iter() + .filter(|entry| entry.pre_name_prefix_len != 0) + .count() + .to_string(), + ); + metadata.insert( + "save_slice.region_collection_nonzero_reserved_policy_count".to_string(), + collection + .entries + .iter() + .filter(|entry| entry.policy_reserved_dwords.iter().any(|raw| *raw != 0)) + .count() + .to_string(), + ); + } let named_locomotive_cost = BTreeMap::new(); let all_cargo_price_override = None; @@ -5589,6 +5636,69 @@ mod tests { } } + fn save_region_collection() -> crate::SmpLoadedRegionCollection { + crate::SmpLoadedRegionCollection { + source_kind: "save-region-record-triplets".to_string(), + semantic_family: "scenario-save-region-triplet-collection".to_string(), + observed_entry_count: 2, + entries: vec![ + crate::SmpLoadedRegionEntry { + record_index: 0, + name: "Marker09".to_string(), + pre_name_prefix_len: 0, + policy_leading_f32_0: 368.0, + policy_leading_f32_1: 0.0, + policy_leading_f32_2: 92.0, + policy_reserved_dwords: vec![0, 0, 0], + policy_trailing_word: 1, + policy_trailing_word_hex: "0x0001".to_string(), + profile_collection: Some(crate::SmpLoadedRegionProfileCollection { + direct_collection_flag: 1, + entry_stride: 0x22, + live_id_bound: 18, + live_record_count: 17, + trailing_padding_len: 2, + entries: vec![ + crate::SmpLoadedRegionProfileEntry { + entry_index: 0, + name: "House".to_string(), + trailing_weight_f32: 0.2, + }, + crate::SmpLoadedRegionProfileEntry { + entry_index: 1, + name: "Farm Corn".to_string(), + trailing_weight_f32: 0.2, + }, + ], + }), + }, + crate::SmpLoadedRegionEntry { + record_index: 1, + name: "Marker10".to_string(), + pre_name_prefix_len: 8, + policy_leading_f32_0: 552.0, + policy_leading_f32_1: 0.0, + policy_leading_f32_2: 276.0, + policy_reserved_dwords: vec![0, 4, 0], + policy_trailing_word: 1, + policy_trailing_word_hex: "0x0001".to_string(), + profile_collection: Some(crate::SmpLoadedRegionProfileCollection { + direct_collection_flag: 1, + entry_stride: 0x22, + live_id_bound: 26, + live_record_count: 24, + trailing_padding_len: 0, + entries: vec![crate::SmpLoadedRegionProfileEntry { + entry_index: 0, + name: "Farm Corn".to_string(), + trailing_weight_f32: 0.2, + }], + }), + }, + ], + } + } + fn save_chairman_profile_table() -> crate::SmpLoadedChairmanProfileTable { crate::SmpLoadedChairmanProfileTable { source_kind: "tracked-save-slice-chairman-profile-table".to_string(), @@ -6088,6 +6198,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -6137,6 +6248,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -6368,6 +6480,7 @@ mod tests { }), company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: Some(crate::SmpLoadedSpecialConditionsTable { @@ -6917,6 +7030,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -6969,6 +7083,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: Some(save_region_collection()), placed_structure_collection: Some(save_placed_structure_collection()), placed_structure_dynamic_side_buffer_summary: Some( save_placed_structure_dynamic_side_buffer_summary(), @@ -6985,6 +7100,46 @@ mod tests { ) .expect("save slice should project"); + assert_eq!( + import + .state + .metadata + .get("save_slice.region_collection_source_kind") + .map(String::as_str), + Some("save-region-record-triplets") + ); + assert_eq!( + import + .state + .metadata + .get("save_slice.region_collection_entry_count") + .map(String::as_str), + Some("2") + ); + assert_eq!( + import + .state + .metadata + .get("save_slice.region_collection_profile_entry_count") + .map(String::as_str), + Some("3") + ); + assert_eq!( + import + .state + .metadata + .get("save_slice.region_collection_nonzero_prefix_count") + .map(String::as_str), + Some("1") + ); + assert_eq!( + import + .state + .metadata + .get("save_slice.region_collection_nonzero_reserved_policy_count") + .map(String::as_str), + Some("1") + ); assert_eq!( import .state @@ -7101,6 +7256,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7274,6 +7430,7 @@ mod tests { selected_chairman_profile_id: Some(1), entries: Vec::new(), }), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7325,6 +7482,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7459,6 +7617,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7571,6 +7730,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7709,6 +7869,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7808,6 +7969,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -7975,6 +8137,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8232,6 +8395,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8324,6 +8488,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8440,6 +8605,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8529,6 +8695,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8621,6 +8788,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8726,6 +8894,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8847,6 +9016,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -8939,6 +9109,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9108,6 +9279,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9222,6 +9394,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9313,6 +9486,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9404,6 +9578,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9569,6 +9744,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9679,6 +9855,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9768,6 +9945,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9867,6 +10045,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -9975,6 +10154,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10091,6 +10271,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10196,6 +10377,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10287,6 +10469,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10448,6 +10631,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10619,6 +10803,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10738,6 +10923,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10838,6 +11024,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -10965,6 +11152,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11086,6 +11274,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11197,6 +11386,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11304,6 +11494,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11425,6 +11616,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11531,6 +11723,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11619,6 +11812,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11712,6 +11906,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11810,6 +12005,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -11908,6 +12104,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -12022,6 +12219,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -12127,6 +12325,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -12279,6 +12478,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -12430,6 +12630,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -12972,6 +13173,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13168,6 +13370,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13309,6 +13512,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13449,6 +13653,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: Some(save_company_roster()), chairman_profile_table: Some(save_chairman_profile_table()), + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13590,6 +13795,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13715,6 +13921,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -13915,6 +14122,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14023,6 +14231,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14133,6 +14342,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14314,6 +14524,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14478,6 +14689,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14583,6 +14795,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14721,6 +14934,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -14847,6 +15061,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -15047,6 +15262,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, @@ -15257,6 +15473,7 @@ mod tests { world_locomotive_policy_state: None, company_roster: None, chairman_profile_table: None, + region_collection: None, placed_structure_collection: None, placed_structure_dynamic_side_buffer_summary: None, special_conditions_table: None, diff --git a/crates/rrt-runtime/src/lib.rs b/crates/rrt-runtime/src/lib.rs index 47f9084..f5f8188 100644 --- a/crates/rrt-runtime/src/lib.rs +++ b/crates/rrt-runtime/src/lib.rs @@ -111,20 +111,21 @@ pub use smp::{ SmpLoadedPackedEventNegativeSentinelScopeSummary, SmpLoadedPackedEventRecordSummary, SmpLoadedPackedEventTextBandSummary, SmpLoadedPlacedStructureCollection, SmpLoadedPlacedStructureDynamicSideBufferSummary, SmpLoadedPlacedStructureEntry, - SmpLoadedProfile, SmpLoadedSaveSlice, SmpLoadedSpecialConditionsTable, - SmpLoadedWorldEconomicTuningState, SmpLoadedWorldFinanceNeighborhoodState, - SmpLoadedWorldIssue37State, SmpLocomotivePolicyFieldObservation, - SmpLocomotivePolicyFloatAlignmentCandidate, SmpLocomotivePolicyNeighborhoodProbe, - SmpPackedProfileWordLane, SmpPeriodicCompanyServiceTraceReport, - SmpPostSpecialConditionsScalarLane, SmpPostSpecialConditionsScalarProbe, - SmpPostTextFieldNeighborhoodProbe, SmpPostTextFloatAlignmentCandidate, - SmpPostTextGroundedFieldObservation, SmpPreRecipeScalarPlateauLane, - SmpPreRecipeScalarPlateauProbe, SmpPreamble, SmpPreambleWord, SmpRecipeBookLineSummary, - SmpRecipeBookSummaryBook, SmpRecipeBookSummaryProbe, SmpRegionServiceTraceReport, - SmpRt3105PackedProfileBlock, SmpRt3105PackedProfileProbe, SmpRt3105PostSpanBridgeProbe, - SmpRt3105SaveBridgePayloadProbe, SmpRt3105SaveNameTableEntry, SmpRt3105SaveNameTableProbe, - SmpRuntimeAnchorCycleBlock, SmpRuntimePostSpanHeaderCandidate, SmpRuntimePostSpanProbe, - SmpRuntimeTrailerBlock, SmpSaveAnchorRunBlock, SmpSaveBootstrapBlock, + SmpLoadedProfile, SmpLoadedRegionCollection, SmpLoadedRegionEntry, + SmpLoadedRegionProfileCollection, SmpLoadedRegionProfileEntry, SmpLoadedSaveSlice, + SmpLoadedSpecialConditionsTable, SmpLoadedWorldEconomicTuningState, + SmpLoadedWorldFinanceNeighborhoodState, SmpLoadedWorldIssue37State, + SmpLocomotivePolicyFieldObservation, SmpLocomotivePolicyFloatAlignmentCandidate, + SmpLocomotivePolicyNeighborhoodProbe, SmpPackedProfileWordLane, + SmpPeriodicCompanyServiceTraceReport, SmpPostSpecialConditionsScalarLane, + SmpPostSpecialConditionsScalarProbe, SmpPostTextFieldNeighborhoodProbe, + SmpPostTextFloatAlignmentCandidate, SmpPostTextGroundedFieldObservation, + SmpPreRecipeScalarPlateauLane, SmpPreRecipeScalarPlateauProbe, SmpPreamble, SmpPreambleWord, + SmpRecipeBookLineSummary, SmpRecipeBookSummaryBook, SmpRecipeBookSummaryProbe, + SmpRegionServiceTraceReport, SmpRt3105PackedProfileBlock, SmpRt3105PackedProfileProbe, + SmpRt3105PostSpanBridgeProbe, SmpRt3105SaveBridgePayloadProbe, SmpRt3105SaveNameTableEntry, + SmpRt3105SaveNameTableProbe, SmpRuntimeAnchorCycleBlock, SmpRuntimePostSpanHeaderCandidate, + SmpRuntimePostSpanProbe, SmpRuntimeTrailerBlock, SmpSaveAnchorRunBlock, SmpSaveBootstrapBlock, SmpSaveChairmanRecordAnalysisEntry, SmpSaveCompanyChairmanAnalysisReport, SmpSaveCompanyRecordAnalysisEntry, SmpSaveDwordCandidate, SmpSaveLoadCandidateTableSummary, SmpSaveLoadSummary, SmpSavePlacedStructureDynamicSideBufferAlignmentProbe, diff --git a/crates/rrt-runtime/src/smp.rs b/crates/rrt-runtime/src/smp.rs index 4592106..9e8f61d 100644 --- a/crates/rrt-runtime/src/smp.rs +++ b/crates/rrt-runtime/src/smp.rs @@ -1749,6 +1749,49 @@ pub struct SmpSaveRegionRecordTripletProbe { pub evidence: Vec, } +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SmpLoadedRegionProfileEntry { + pub entry_index: usize, + pub name: String, + pub trailing_weight_f32: f32, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SmpLoadedRegionProfileCollection { + pub direct_collection_flag: u32, + pub entry_stride: u32, + pub live_id_bound: u32, + pub live_record_count: u32, + pub trailing_padding_len: usize, + #[serde(default)] + pub entries: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SmpLoadedRegionEntry { + pub record_index: usize, + pub name: String, + pub pre_name_prefix_len: usize, + pub policy_leading_f32_0: f32, + pub policy_leading_f32_1: f32, + pub policy_leading_f32_2: f32, + #[serde(default)] + pub policy_reserved_dwords: Vec, + pub policy_trailing_word: u16, + pub policy_trailing_word_hex: String, + #[serde(default)] + pub profile_collection: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SmpLoadedRegionCollection { + pub source_kind: String, + pub semantic_family: String, + pub observed_entry_count: usize, + #[serde(default)] + pub entries: Vec, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct SmpSaveRegionQueuedNoticeRecordEntryProbe { pub node_base_offset: usize, @@ -4058,7 +4101,7 @@ enum RealGroupedTargetSubject { WholeGame, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct SmpLoadedSaveSlice { pub file_extension_hint: Option, pub container_profile_family: Option, @@ -4086,6 +4129,8 @@ pub struct SmpLoadedSaveSlice { #[serde(default)] pub chairman_profile_table: Option, #[serde(default)] + pub region_collection: Option, + #[serde(default)] pub placed_structure_collection: Option, #[serde(default)] pub placed_structure_dynamic_side_buffer_summary: @@ -6909,6 +6954,49 @@ fn derive_loaded_placed_structure_collection_from_probe( } } +fn derive_loaded_region_collection_from_probe( + probe: &SmpSaveRegionRecordTripletProbe, +) -> SmpLoadedRegionCollection { + SmpLoadedRegionCollection { + source_kind: probe.source_kind.clone(), + semantic_family: "scenario-save-region-triplet-collection".to_string(), + observed_entry_count: probe.record_count, + entries: probe + .entries + .iter() + .map(|entry| SmpLoadedRegionEntry { + record_index: entry.record_index, + name: entry.name.clone(), + pre_name_prefix_len: entry.pre_name_prefix_len, + policy_leading_f32_0: entry.policy_leading_f32_0, + policy_leading_f32_1: entry.policy_leading_f32_1, + policy_leading_f32_2: entry.policy_leading_f32_2, + policy_reserved_dwords: entry.policy_reserved_dwords.clone(), + policy_trailing_word: entry.policy_trailing_word, + policy_trailing_word_hex: entry.policy_trailing_word_hex.clone(), + profile_collection: entry.profile_collection.as_ref().map(|collection| { + SmpLoadedRegionProfileCollection { + direct_collection_flag: collection.direct_collection_flag, + entry_stride: collection.entry_stride, + live_id_bound: collection.live_id_bound, + live_record_count: collection.live_record_count, + trailing_padding_len: collection.trailing_padding_len, + entries: collection + .entries + .iter() + .map(|entry| SmpLoadedRegionProfileEntry { + entry_index: entry.entry_index, + name: entry.name.clone(), + trailing_weight_f32: entry.trailing_weight_f32, + }) + .collect(), + } + }), + }) + .collect(), + } +} + fn derive_loaded_placed_structure_dynamic_side_buffer_summary( probe: &SmpSavePlacedStructureDynamicSideBufferProbe, alignment: Option<&SmpSavePlacedStructureDynamicSideBufferAlignmentProbe>, @@ -7082,6 +7170,10 @@ pub fn load_save_slice_from_report( ) }) }); + let region_collection = report + .save_region_record_triplet_probe + .as_ref() + .map(derive_loaded_region_collection_from_probe); let placed_structure_collection = report .save_placed_structure_record_triplet_probe .as_ref() @@ -7246,6 +7338,36 @@ pub fn load_save_slice_from_report( }) )); } + if let Some(collection) = ®ion_collection { + let total_profile_rows = collection + .entries + .iter() + .map(|entry| { + entry + .profile_collection + .as_ref() + .map(|collection| collection.entries.len()) + .unwrap_or_default() + }) + .sum::(); + let nonzero_prefix_count = collection + .entries + .iter() + .filter(|entry| entry.pre_name_prefix_len != 0) + .count(); + let nonzero_reserved_count = collection + .entries + .iter() + .filter(|entry| entry.policy_reserved_dwords.iter().any(|raw| *raw != 0)) + .count(); + notes.push(format!( + "Save-slice projection now carries {} loaded region triplet rows as first-class context, with {} embedded profile rows, {} rows with nonzero pre-name prefixes, and {} rows with nonzero reserved policy dwords.", + collection.observed_entry_count, + total_profile_rows, + nonzero_prefix_count, + nonzero_reserved_count + )); + } if let Some(probe) = &report.save_placed_structure_collection_header_probe { notes.push(format!( "Raw save tagged placed-structure header reports live_record_count={} and live_id_bound={} with serialized stride hint 0x{:x} at file offsets 0x{:x}/0x{:x}/0x{:x}.", @@ -7392,6 +7514,7 @@ pub fn load_save_slice_from_report( world_locomotive_policy_state, company_roster, chairman_profile_table, + region_collection, placed_structure_collection, placed_structure_dynamic_side_buffer_summary, special_conditions_table, @@ -25441,6 +25564,100 @@ mod tests { None, None, ); + report.save_region_record_triplet_probe = Some(SmpSaveRegionRecordTripletProbe { + profile_family: "rt3-classic-save-container-v1".to_string(), + source_kind: "save-region-record-triplets".to_string(), + semantic_family: "scenario-save-region-record-triplets".to_string(), + records_tag_offset: 0x3400, + close_tag_offset: 0x3500, + record_count: 2, + entries: vec![ + SmpSaveRegionRecordTripletEntryProbe { + record_index: 0, + name: "Marker09".to_string(), + record_payload_relative_offset: 0, + record_payload_relative_offset_hex: "0x0".to_string(), + name_tag_relative_offset: 0, + policy_tag_relative_offset: 0x10, + profile_tag_relative_offset: 0x2e, + pre_name_prefix_len: 0, + pre_name_prefix_hex_bytes: Vec::new(), + pre_name_prefix_dword_candidates: Vec::new(), + policy_chunk_len: 0x1a, + profile_chunk_len: 0x40, + policy_leading_f32_0: 368.0, + policy_leading_f32_1: 0.0, + policy_leading_f32_2: 92.0, + policy_reserved_dwords: vec![0, 0, 0], + policy_reserved_dword_candidates: Vec::new(), + policy_trailing_word: 1, + policy_trailing_word_hex: "0x0001".to_string(), + profile_collection: Some(SmpSaveRegionProfileCollectionProbe { + direct_collection_flag: 1, + entry_stride: 0x22, + live_id_bound: 18, + live_record_count: 17, + entry_start_relative_offset: 0x4d, + trailing_padding_len: 2, + entries: vec![ + SmpSaveRegionProfileEntryProbe { + entry_index: 0, + row_relative_offset: 0x4d, + name: "House".to_string(), + trailing_weight_f32: 0.2, + }, + SmpSaveRegionProfileEntryProbe { + entry_index: 1, + row_relative_offset: 0x6f, + name: "Farm Corn".to_string(), + trailing_weight_f32: 0.2, + }, + ], + }), + }, + SmpSaveRegionRecordTripletEntryProbe { + record_index: 1, + name: "Marker10".to_string(), + record_payload_relative_offset: 0x6e, + record_payload_relative_offset_hex: "0x6e".to_string(), + name_tag_relative_offset: 0x76, + policy_tag_relative_offset: 0x86, + profile_tag_relative_offset: 0xa4, + pre_name_prefix_len: 8, + pre_name_prefix_hex_bytes: vec![ + "0xaa".to_string(), + "0xbb".to_string(), + "0xcc".to_string(), + "0xdd".to_string(), + ], + pre_name_prefix_dword_candidates: Vec::new(), + policy_chunk_len: 0x1a, + profile_chunk_len: 0x20, + policy_leading_f32_0: 552.0, + policy_leading_f32_1: 0.0, + policy_leading_f32_2: 276.0, + policy_reserved_dwords: vec![0, 4, 0], + policy_reserved_dword_candidates: Vec::new(), + policy_trailing_word: 1, + policy_trailing_word_hex: "0x0001".to_string(), + profile_collection: Some(SmpSaveRegionProfileCollectionProbe { + direct_collection_flag: 1, + entry_stride: 0x22, + live_id_bound: 26, + live_record_count: 24, + entry_start_relative_offset: 0x50, + trailing_padding_len: 0, + entries: vec![SmpSaveRegionProfileEntryProbe { + entry_index: 0, + row_relative_offset: 0x50, + name: "Farm Corn".to_string(), + trailing_weight_f32: 0.2, + }], + }), + }, + ], + evidence: vec![], + }); report.save_placed_structure_record_triplet_probe = Some(SmpSavePlacedStructureRecordTripletProbe { profile_family: "rt3-classic-save-container-v1".to_string(), @@ -25604,6 +25821,24 @@ mod tests { evidence: vec![], }); let slice = load_save_slice_from_report(&report).expect("classic save slice"); + let region_collection = slice + .region_collection + .expect("region collection should project"); + assert_eq!(region_collection.source_kind, "save-region-record-triplets"); + assert_eq!(region_collection.observed_entry_count, 2); + assert_eq!(region_collection.entries[0].name, "Marker09"); + assert_eq!(region_collection.entries[1].pre_name_prefix_len, 8); + assert_eq!( + region_collection.entries[1].policy_reserved_dwords, + vec![0, 4, 0] + ); + assert_eq!( + region_collection.entries[0] + .profile_collection + .as_ref() + .map(|collection| collection.entries.len()), + Some(2) + ); let collection = slice .placed_structure_collection .expect("placed structure collection should project"); @@ -25629,6 +25864,10 @@ mod tests { side_buffer_summary.triplet_alignment_side_buffer_only_name_pair_count, 0 ); + assert!(slice.notes.iter().any(|line| { + line.contains("loaded region triplet rows as first-class context") + && line.contains("3 embedded profile rows") + })); assert!(slice.notes.iter().any(|line| { line.contains("placed-structure triplet rows as first-class context") && line.contains("2") diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index 832104b..b7c1ac0 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -84,6 +84,10 @@ Working rule: model as first-class `placed_structure_dynamic_side_buffer_summary` context, carrying the grounded owner-shared dword, compact-prefix summaries, name-pair summaries, and overlap counts against the triplet corpus instead of remaining trace-only evidence + - the save-side `0x55f1/0x55f2/0x55f3` region triplet seam is now also loaded into the + save-slice model as first-class `region_collection` context, carrying region names, the + grounded policy lanes, reserved-policy dwords, and embedded profile rows instead of leaving + region triplets inspection-only - Direct disassembly now narrows that acquisition strip further: - `0x004014b0` scans the live placed-structure collection at `0x0062b26c` - `0x0041f6e0 -> 0x0042b2d0` is the center-cell token gate over the current region