rrt/crates/rrt-runtime/src/smp.rs

28448 lines
1.2 MiB

use std::cmp::Reverse;
use std::collections::{BTreeMap, BTreeSet};
use std::fs;
use std::path::Path;
use std::sync::OnceLock;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::{
RuntimeCargoClass, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCompanyConditionTestScope,
RuntimeCompanyControllerKind, RuntimeCompanyMarketState, RuntimeCompanyMetric,
RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator, RuntimeEffect,
RuntimeEventRecordTemplate, RuntimePlayerConditionTestScope, RuntimePlayerTarget,
RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
};
pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec;
const PREAMBLE_U32_WORD_COUNT: usize = 16;
const MIN_ASCII_RUN_LEN: usize = 8;
const ASCII_PREVIEW_CHAR_LIMIT: usize = 160;
const TAG_OFFSET_SAMPLE_LIMIT: usize = 8;
const EARLY_ZERO_RUN_THRESHOLD: usize = 16;
const EARLY_PREVIEW_BYTE_LIMIT: usize = 32;
const EARLY_ALIGNED_WORD_WINDOW_COUNT: usize = 8;
const SPECIAL_CONDITIONS_OFFSET: usize = 0x0d64;
const SPECIAL_CONDITION_COUNT: usize = 36;
const SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT: usize = 35;
const SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT: usize = 50;
const SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT: usize = 49;
const SMP_ALIGNED_RUNTIME_RULE_RUNTIME_OBJECT_OFFSET: usize = 0x4a7f;
const SMP_ALIGNED_RUNTIME_RULE_END_OFFSET: usize =
SPECIAL_CONDITIONS_OFFSET + SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT * 4;
const POST_SPECIAL_CONDITIONS_SCALAR_OFFSET: usize = 0x0df4;
const POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET: usize = 0x0f30;
const POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET: usize = 0x0f58;
const POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET: usize =
SMP_ALIGNED_RUNTIME_RULE_END_OFFSET;
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET: usize = SMP_ALIGNED_RUNTIME_RULE_END_OFFSET;
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_OFFSET: usize =
SMP_ALIGNED_RUNTIME_RULE_RUNTIME_OBJECT_OFFSET
+ (POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET - SPECIAL_CONDITIONS_OFFSET);
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET: usize =
SMP_ALIGNED_RUNTIME_RULE_RUNTIME_OBJECT_OFFSET
+ (POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET - SPECIAL_CONDITIONS_OFFSET);
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET: usize = 0x4b47;
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN: usize = 0x12c;
const POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET: usize =
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET
+ POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN;
const POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET: usize = 0x0f59;
const POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET: usize = 0x0f75;
const POST_TEXT_FIELD_0_RUNTIME_OBJECT_OFFSET: usize = 0x4c74;
const POST_TEXT_FIELD_1_RUNTIME_OBJECT_OFFSET: usize = 0x4c78;
const POST_TEXT_FIELD_2_RUNTIME_OBJECT_OFFSET: usize = 0x4c7c;
const POST_TEXT_FIELD_3_RUNTIME_OBJECT_OFFSET: usize = 0x4c80;
const POST_TEXT_FIELD_4_RUNTIME_OBJECT_OFFSET: usize = 0x4c88;
const POST_TEXT_FIELD_5_RUNTIME_OBJECT_OFFSET: usize = 0x4c8c;
const POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET: usize = 0x4c80;
const POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_OFFSET: usize = 0x4c8c;
const POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_FILE_OFFSET: usize =
SPECIAL_CONDITIONS_OFFSET
+ (POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET
- SMP_ALIGNED_RUNTIME_RULE_RUNTIME_OBJECT_OFFSET);
const POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_FILE_OFFSET: usize =
SPECIAL_CONDITIONS_OFFSET
+ (POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_OFFSET
- SMP_ALIGNED_RUNTIME_RULE_RUNTIME_OBJECT_OFFSET);
const LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET: usize = 0x0f78;
const LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET: usize = 0x0fa7;
const LOCOMOTIVE_POLICY_FIELD_NEG3_RUNTIME_OBJECT_OFFSET: usize = 0x4ca2;
const LOCOMOTIVE_POLICY_FIELD_NEG2_RUNTIME_OBJECT_OFFSET: usize = 0x4cae;
const LOCOMOTIVE_POLICY_FIELD_NEG1_RUNTIME_OBJECT_OFFSET: usize = 0x4cb2;
const LOCOMOTIVE_POLICY_FIELD_0_RUNTIME_OBJECT_OFFSET: usize = 0x4c93;
const LOCOMOTIVE_POLICY_FIELD_1_RUNTIME_OBJECT_OFFSET: usize = 0x4c97;
const LOCOMOTIVE_POLICY_FIELD_2_RUNTIME_OBJECT_OFFSET: usize = 0x4c98;
const LOCOMOTIVE_POLICY_FIELD_3_RUNTIME_OBJECT_OFFSET: usize = 0x4c99;
const LOCOMOTIVE_POLICY_FIELD_4_RUNTIME_OBJECT_OFFSET: usize = 0x4cba;
const LOCOMOTIVE_POLICY_FIELD_5_RUNTIME_OBJECT_OFFSET: usize = 0x4cbe;
const PRE_RECIPE_SCALAR_PLATEAU_OFFSET: usize = 0x0fa7;
const PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET: usize = 0x0fe7;
const RECIPE_BOOK_ROOT_OFFSET: usize = 0x0fe7;
const RECIPE_BOOK_COUNT: usize = 12;
const RECIPE_BOOK_STRIDE: usize = 0x4e1;
const RECIPE_BOOK_HEAD_SAMPLE_LEN: usize = 16;
const RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET: usize = 0x3ed;
const RECIPE_BOOK_LINE_AREA_OFFSET: usize = 0x3f1;
const RECIPE_BOOK_LINE_COUNT: usize = 5;
const RECIPE_BOOK_LINE_STRIDE: usize = 0x30;
const RECIPE_BOOK_LINE_AREA_LEN: usize = RECIPE_BOOK_LINE_COUNT * RECIPE_BOOK_LINE_STRIDE;
const RECIPE_BOOK_SUMMARY_END_OFFSET: usize =
RECIPE_BOOK_ROOT_OFFSET + RECIPE_BOOK_COUNT * RECIPE_BOOK_STRIDE;
const RT3_SAVE_WORLD_BLOCK_CHUNK_TAG: u32 = 0x000032c8;
const RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG: u32 = 0x000032c9;
const RT3_SAVE_WORLD_BLOCK_LEN: usize = 0x4f2c;
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_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),
("issue_0x37_value", 0x29),
("issue_neighbor_candidate_0", 0x2d),
("issue_neighbor_candidate_1", 0x31),
("issue_neighbor_candidate_2", 0x35),
];
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_ISSUE_OPINION_BASE_TERMS_OFFSET: usize = 0x8a;
const RT3_SAVE_WORLD_BLOCK_ISSUE_OPINION_TERM_COUNT: usize = 0x3b;
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;
const RT3_SAVE_WORLD_BLOCK_STOCK_POLICY_RELATIVE_OFFSET: usize = 0x4a83;
const RT3_SAVE_WORLD_BLOCK_BOND_POLICY_RELATIVE_OFFSET: usize = 0x4a87;
const RT3_SAVE_WORLD_BLOCK_BANKRUPTCY_POLICY_RELATIVE_OFFSET: usize = 0x4a8b;
const RT3_SAVE_WORLD_BLOCK_DIVIDEND_POLICY_RELATIVE_OFFSET: usize = 0x4a8f;
const RT3_SAVE_WORLD_BLOCK_BUILDING_DENSITY_GROWTH_RELATIVE_OFFSET: usize = 0x4c78;
const RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_MIRROR_RELATIVE_OFFSET: usize = 0x0bda;
const RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_PRIMARY_RELATIVE_OFFSETS: [usize; 6] =
[0x0bde, 0x0be2, 0x0be6, 0x0bea, 0x0bee, 0x0bf2];
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT: usize = 16;
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE: usize = 9;
const EVENT_RUNTIME_COLLECTION_METADATA_TAG: u16 = 0x4e99;
const EVENT_RUNTIME_COLLECTION_RECORDS_TAG: u16 = 0x4e9a;
const EVENT_RUNTIME_COLLECTION_CLOSE_TAG: u16 = 0x4e9b;
const EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION: u32 = 0x000003e9;
const INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT: usize = 19;
const INDEXED_COLLECTION_SERIALIZED_HEADER_LEN: usize =
INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT * 4;
const SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX: usize = 16;
const SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT: usize = 3;
const SAVE_REGION_RECORD_NAME_TAG: u16 = 0x55f1;
const SAVE_REGION_RECORD_POLICY_TAG: u16 = 0x55f2;
const SAVE_REGION_RECORD_PROFILE_TAG: u16 = 0x55f3;
const SAVE_REGION_FIXED_ROW_STRIDE: usize = 0x29;
const SAVE_REGION_FIXED_ROW_DWORD_LANE_COUNT: usize = SAVE_REGION_FIXED_ROW_STRIDE / 4;
const SAVE_REGION_FIXED_ROW_CANDIDATE_PROBE_LIMIT: usize = 24;
const SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED: u32 = 0x005c87a8;
const SAVE_REGION_QUEUED_NOTICE_NODE_KIND: u32 = 7;
const SAVE_REGION_QUEUED_NOTICE_NODE_LEN: usize = 0x20;
const PACKED_EVENT_RECORDS_SYNTHETIC_MAGIC: &[u8; 8] = b"RPEVT001";
const PACKED_EVENT_RECORD_SYNTHETIC_MAGIC: &[u8; 4] = b"RPE1";
const PACKED_EVENT_RECORD_TEMPLATE_SYNTHETIC_MAGIC: &[u8; 4] = b"RPT1";
const PACKED_EVENT_REAL_CONDITION_MARKER: u16 = 0x526f;
const PACKED_EVENT_REAL_GROUPED_EFFECT_MARKER: u16 = 0x4eb8;
const PACKED_EVENT_REAL_CONDITION_ROW_LEN: usize = 0x1e;
const PACKED_EVENT_REAL_GROUPED_EFFECT_ROW_LEN: usize = 0x28;
const PACKED_EVENT_REAL_GROUP_COUNT: usize = 4;
const PACKED_EVENT_REAL_COMPACT_CONTROL_LEN: usize = 37;
const PACKED_EVENT_TEXT_BAND_LABELS: [&str; 6] = [
"primary_text_band",
"secondary_text_band_0",
"secondary_text_band_1",
"secondary_text_band_2",
"secondary_text_band_3",
"secondary_text_band_4",
];
const SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX: usize =
(POST_SPECIAL_CONDITIONS_SCALAR_OFFSET - SPECIAL_CONDITIONS_OFFSET) / 4;
const SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT: usize =
(SMP_ALIGNED_RUNTIME_RULE_END_OFFSET - POST_SPECIAL_CONDITIONS_SCALAR_OFFSET) / 4;
const SHARED_SIGNATURE_WORDS_1_TO_7: [u32; 7] = [
0x00002ee0, 0x00040001, 0x00028000, 0x00010000, 0x00000771, 0x00000771, 0x00000771,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct RealGroupedEffectDescriptorMetadata {
descriptor_id: u32,
label: &'static str,
target_mask_bits: u8,
parameter_family: &'static str,
runtime_key: Option<&'static str>,
runtime_status: RealGroupedEffectRuntimeStatus,
executable_in_runtime: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RealGroupedEffectRuntimeStatus {
Executable,
ShellOwned,
EvidenceBlocked,
VariantOrScopeBlocked,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
struct CheckedInEventEffectsSemanticCatalogArtifact {
descriptors: Vec<CheckedInEventEffectSemanticRow>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
struct CheckedInEventEffectSemanticRow {
descriptor_id: u32,
label: String,
target_mask_bits: u8,
parameter_family: String,
runtime_key: Option<String>,
runtime_status: String,
executable_in_runtime: bool,
}
const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetadata; 12] = [
RealGroupedEffectDescriptorMetadata {
descriptor_id: 1,
label: "Player Cash",
target_mask_bits: 0x02,
parameter_family: "player_finance_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 2,
label: "Company Cash",
target_mask_bits: 0x01,
parameter_family: "company_finance_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 3,
label: "Territory - Allow All",
target_mask_bits: 0x05,
parameter_family: "territory_access_toggle",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 8,
label: "Economic Status",
target_mask_bits: 0x08,
parameter_family: "whole_game_state_enum",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 108,
label: "Use Wartime Cargos",
target_mask_bits: 0x08,
parameter_family: "special_condition_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 109,
label: "Turbo Diesel Availability",
target_mask_bits: 0x08,
parameter_family: "candidate_availability_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 110,
label: "Disable Stock Buying and Selling",
target_mask_bits: 0x08,
parameter_family: "world_flag_toggle",
runtime_key: Some("world.disable_stock_buying_and_selling"),
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 9,
label: "Confiscate All",
target_mask_bits: 0x01,
parameter_family: "company_confiscation_variant",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 13,
label: "Deactivate Company",
target_mask_bits: 0x01,
parameter_family: "company_lifecycle_toggle",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 14,
label: "Deactivate Player",
target_mask_bits: 0x02,
parameter_family: "player_lifecycle_toggle",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 15,
label: "Retire Train",
target_mask_bits: 0x0d,
parameter_family: "company_or_territory_asset_toggle",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
RealGroupedEffectDescriptorMetadata {
descriptor_id: 16,
label: "Company Track Pieces Buildable",
target_mask_bits: 0x01,
parameter_family: "company_build_limit_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
},
];
fn real_grouped_effect_runtime_status_name(status: RealGroupedEffectRuntimeStatus) -> &'static str {
match status {
RealGroupedEffectRuntimeStatus::Executable => "executable",
RealGroupedEffectRuntimeStatus::ShellOwned => "shell_owned",
RealGroupedEffectRuntimeStatus::EvidenceBlocked => "evidence_blocked",
RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked => "variant_or_scope_blocked",
}
}
fn checked_in_event_effect_descriptor_rows()
-> &'static BTreeMap<u32, RealGroupedEffectDescriptorMetadata> {
static ROWS: OnceLock<BTreeMap<u32, RealGroupedEffectDescriptorMetadata>> = OnceLock::new();
ROWS.get_or_init(|| {
let artifact: CheckedInEventEffectsSemanticCatalogArtifact = serde_json::from_str(
include_str!("../../../artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json"),
)
.expect("checked-in event-effects semantic catalog should parse");
artifact
.descriptors
.into_iter()
.map(|row| {
(
row.descriptor_id,
checked_in_event_effect_descriptor_metadata(row),
)
})
.collect()
})
}
fn checked_in_event_effect_descriptor_metadata(
row: CheckedInEventEffectSemanticRow,
) -> RealGroupedEffectDescriptorMetadata {
let label = Box::leak(row.label.clone().into_boxed_str()) as &'static str;
let parameter_family = Box::leak(row.parameter_family.into_boxed_str()) as &'static str;
let runtime_key = row
.runtime_key
.map(|key| Box::leak(key.into_boxed_str()) as &'static str);
let runtime_status = match row.runtime_status.as_str() {
"executable" => RealGroupedEffectRuntimeStatus::Executable,
"shell_owned" => RealGroupedEffectRuntimeStatus::ShellOwned,
"evidence_blocked" => RealGroupedEffectRuntimeStatus::EvidenceBlocked,
"variant_or_scope_blocked" => RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked,
other => panic!("unknown checked-in event-effect runtime status {other}"),
};
RealGroupedEffectDescriptorMetadata {
descriptor_id: row.descriptor_id,
label,
target_mask_bits: row.target_mask_bits,
parameter_family,
runtime_key,
runtime_status,
executable_in_runtime: row.executable_in_runtime,
}
}
pub(crate) fn grouped_effect_descriptor_runtime_status_name(
descriptor_id: u32,
) -> Option<&'static str> {
real_grouped_effect_descriptor_metadata(descriptor_id)
.map(|metadata| real_grouped_effect_runtime_status_name(metadata.runtime_status))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RealOrdinaryConditionMetric {
WorldVariable(u32),
Company(RuntimeCompanyMetric),
CompanyVariable(u32),
PlayerVariable(u32),
Chairman(RuntimeChairmanMetric),
Territory(RuntimeTerritoryMetric),
TerritoryVariable(u32),
CompanyTerritory(RuntimeTrackMetric),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RealWorldConditionKind {
SpecialCondition { label: &'static str },
CandidateAvailability,
NamedLocomotiveAvailability,
NamedLocomotiveCost,
CargoProductionSlot,
CargoProductionTotal,
FactoryProductionTotal,
FarmMineProductionTotal,
OtherCargoProductionTotal,
LimitedTrackBuildingAmount,
TerritoryAccessCost,
EconomicStatus,
WorldFlag { key: &'static str },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RealOrdinaryConditionKind {
Numeric(RealOrdinaryConditionMetric),
WorldState(RealWorldConditionKind),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct RealOrdinaryConditionMetadata {
raw_condition_id: i32,
label: &'static str,
kind: RealOrdinaryConditionKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct KnownCargoSlotDefinition {
slot_id: u32,
label: &'static str,
cargo_class: RuntimeCargoClass,
descriptor_id: u32,
}
const KNOWN_CARGO_SLOT_DEFINITIONS: [KnownCargoSlotDefinition; 11] = [
KnownCargoSlotDefinition {
slot_id: 1,
label: "Cargo Production Slot 1",
cargo_class: RuntimeCargoClass::Factory,
descriptor_id: 230,
},
KnownCargoSlotDefinition {
slot_id: 2,
label: "Cargo Production Slot 2",
cargo_class: RuntimeCargoClass::Factory,
descriptor_id: 231,
},
KnownCargoSlotDefinition {
slot_id: 3,
label: "Cargo Production Slot 3",
cargo_class: RuntimeCargoClass::Factory,
descriptor_id: 232,
},
KnownCargoSlotDefinition {
slot_id: 4,
label: "Cargo Production Slot 4",
cargo_class: RuntimeCargoClass::Factory,
descriptor_id: 233,
},
KnownCargoSlotDefinition {
slot_id: 5,
label: "Cargo Production Slot 5",
cargo_class: RuntimeCargoClass::FarmMine,
descriptor_id: 234,
},
KnownCargoSlotDefinition {
slot_id: 6,
label: "Cargo Production Slot 6",
cargo_class: RuntimeCargoClass::FarmMine,
descriptor_id: 235,
},
KnownCargoSlotDefinition {
slot_id: 7,
label: "Cargo Production Slot 7",
cargo_class: RuntimeCargoClass::FarmMine,
descriptor_id: 236,
},
KnownCargoSlotDefinition {
slot_id: 8,
label: "Cargo Production Slot 8",
cargo_class: RuntimeCargoClass::FarmMine,
descriptor_id: 237,
},
KnownCargoSlotDefinition {
slot_id: 9,
label: "Cargo Production Slot 9",
cargo_class: RuntimeCargoClass::Other,
descriptor_id: 238,
},
KnownCargoSlotDefinition {
slot_id: 10,
label: "Cargo Production Slot 10",
cargo_class: RuntimeCargoClass::Other,
descriptor_id: 239,
},
KnownCargoSlotDefinition {
slot_id: 11,
label: "Cargo Production Slot 11",
cargo_class: RuntimeCargoClass::Other,
descriptor_id: 240,
},
];
const GROUNDED_LOCOMOTIVE_PREFIX: [&str; 61] = [
"2-D-2",
"E-88",
"Adler 2-2-2",
"USA 103",
"American 4-4-0",
"Atlantic 4-4-2",
"Baldwin 0-6-0",
"Be 5/7",
"Beuth 2-2-2",
"Big Boy 4-8-8-4",
"C55 Deltic",
"Camelback 0-6-0",
"Challenger 4-6-6-4",
"Class 01 4-6-2",
"Class 103",
"Class 132",
"Class 500 4-6-0",
"Class 9100",
"Class EF 66",
"Class 6E",
"Consolidation 2-8-0",
"Crampton 4-2-0",
"DD 080-X",
"DD40AX",
"Duke Class 4-4-0",
"E18",
"E428",
"Brenner E412",
"E60CP",
"Eight Wheeler 4-4-0",
"EP-2 Bipolar",
"ET22",
"F3",
"Fairlie 0-6-6-0",
"Firefly 2-2-2",
"FP45",
"Ge 6/6 Crocodile",
"GG1",
"GP7",
"H10 2-8-2",
"HST 125",
"Kriegslok 2-10-0",
"Mallard 4-6-2",
"Norris 4-2-0",
"Northern 4-8-4",
"Orca NX462",
"Pacific 4-6-2",
"Planet 2-2-0",
"Re 6/6",
"Red Devil 4-8-4",
"S3 4-4-0",
"NA-90D",
"Shay (2-Truck)",
"Shinkansen Series 0",
"Stirling 4-2-2",
"Trans-Euro",
"V200",
"VL80T",
"GP 35",
"U1",
"Zephyr",
];
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
const REAL_WORLD_VARIABLE_1_CONDITION_ID: i32 = 2241;
const REAL_WORLD_VARIABLE_2_CONDITION_ID: i32 = 2242;
const REAL_WORLD_VARIABLE_3_CONDITION_ID: i32 = 2243;
const REAL_WORLD_VARIABLE_4_CONDITION_ID: i32 = 2244;
const REAL_COMPANY_VARIABLE_1_CONDITION_ID: i32 = 2245;
const REAL_COMPANY_VARIABLE_2_CONDITION_ID: i32 = 2246;
const REAL_COMPANY_VARIABLE_3_CONDITION_ID: i32 = 2247;
const REAL_COMPANY_VARIABLE_4_CONDITION_ID: i32 = 2248;
const REAL_PLAYER_VARIABLE_1_CONDITION_ID: i32 = 2249;
const REAL_PLAYER_VARIABLE_2_CONDITION_ID: i32 = 2250;
const REAL_PLAYER_VARIABLE_3_CONDITION_ID: i32 = 2251;
const REAL_PLAYER_VARIABLE_4_CONDITION_ID: i32 = 2252;
const REAL_TERRITORY_VARIABLE_1_CONDITION_ID: i32 = 2253;
const REAL_TERRITORY_VARIABLE_2_CONDITION_ID: i32 = 2254;
const REAL_TERRITORY_VARIABLE_3_CONDITION_ID: i32 = 2255;
const REAL_TERRITORY_VARIABLE_4_CONDITION_ID: i32 = 2256;
const REAL_CHAIRMAN_CASH_CONDITION_ID: i32 = 2218;
const REAL_CHAIRMAN_HOLDINGS_TOTAL_CONDITION_ID: i32 = 2239;
const REAL_CHAIRMAN_NET_WORTH_CONDITION_ID: i32 = 2240;
const REAL_CHAIRMAN_PURCHASING_POWER_CONDITION_ID: i32 = 1247;
const REAL_INVESTOR_CONFIDENCE_CONDITION_ID: i32 = 2366;
const REAL_CREDIT_RATING_CONDITION_ID: i32 = 2367;
const REAL_PRIME_RATE_CONDITION_ID: i32 = 2368;
const REAL_MANAGEMENT_ATTITUDE_CONDITION_ID: i32 = 2369;
const REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID: i32 = 2620;
const REAL_CARGO_PRODUCTION_CONDITION_TEMPLATE_ID: i32 = 200;
const REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID: i32 = 2422;
const REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID: i32 = 2423;
const REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2418;
const REAL_FACTORY_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2419;
const REAL_FARM_MINE_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2420;
const REAL_OTHER_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2421;
const REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID: i32 = 2547;
const REAL_TERRITORY_ACCESS_COST_CONDITION_ID: i32 = 1516;
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 56] = [
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_WORLD_VARIABLE_1_CONDITION_ID,
label: "Game Variable 1",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::WorldVariable(1)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_WORLD_VARIABLE_2_CONDITION_ID,
label: "Game Variable 2",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::WorldVariable(2)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_WORLD_VARIABLE_3_CONDITION_ID,
label: "Game Variable 3",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::WorldVariable(3)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_WORLD_VARIABLE_4_CONDITION_ID,
label: "Game Variable 4",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::WorldVariable(4)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_COMPANY_VARIABLE_1_CONDITION_ID,
label: "Company Variable 1",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyVariable(1)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_COMPANY_VARIABLE_2_CONDITION_ID,
label: "Company Variable 2",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyVariable(2)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_COMPANY_VARIABLE_3_CONDITION_ID,
label: "Company Variable 3",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyVariable(3)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_COMPANY_VARIABLE_4_CONDITION_ID,
label: "Company Variable 4",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyVariable(4)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_PLAYER_VARIABLE_1_CONDITION_ID,
label: "Player Variable 1",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::PlayerVariable(1)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_PLAYER_VARIABLE_2_CONDITION_ID,
label: "Player Variable 2",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::PlayerVariable(2)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_PLAYER_VARIABLE_3_CONDITION_ID,
label: "Player Variable 3",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::PlayerVariable(3)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_PLAYER_VARIABLE_4_CONDITION_ID,
label: "Player Variable 4",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::PlayerVariable(4)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_VARIABLE_1_CONDITION_ID,
label: "Territory Variable 1",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::TerritoryVariable(1)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_VARIABLE_2_CONDITION_ID,
label: "Territory Variable 2",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::TerritoryVariable(2)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_VARIABLE_3_CONDITION_ID,
label: "Territory Variable 3",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::TerritoryVariable(3)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_VARIABLE_4_CONDITION_ID,
label: "Territory Variable 4",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::TerritoryVariable(4)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 1802,
label: "Current Cash",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::CurrentCash,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CHAIRMAN_CASH_CONDITION_ID,
label: "Player Cash",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Chairman(
RuntimeChairmanMetric::CurrentCash,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CHAIRMAN_HOLDINGS_TOTAL_CONDITION_ID,
label: "Player Stock Value",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Chairman(
RuntimeChairmanMetric::HoldingsValueTotal,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CHAIRMAN_NET_WORTH_CONDITION_ID,
label: "Player Net Worth",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Chairman(
RuntimeChairmanMetric::NetWorthTotal,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CHAIRMAN_PURCHASING_POWER_CONDITION_ID,
label: "Purchasing Power",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Chairman(
RuntimeChairmanMetric::PurchasingPowerTotal,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 951,
label: "Total Debt",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TotalDebt,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_INVESTOR_CONFIDENCE_CONDITION_ID,
label: "Investor Confidence",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::InvestorConfidence,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CREDIT_RATING_CONDITION_ID,
label: "Credit Rating",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::CreditRating,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_PRIME_RATE_CONDITION_ID,
label: "Prime Rate",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::PrimeRate,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_MANAGEMENT_ATTITUDE_CONDITION_ID,
label: "Management Attitude",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::ManagementAttitude,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID,
label: "Book Value Per Share",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::BookValuePerShare,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2293,
label: "Company Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesTotal,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2294,
label: "Company Single Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesSingle,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2295,
label: "Company Double Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesDouble,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2296,
label: "Company Transition Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesTransition,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2297,
label: "Company Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesElectric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2298,
label: "Company Non-Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(
RuntimeCompanyMetric::TrackPiecesNonElectric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2313,
label: "Territory Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesTotal,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2314,
label: "Territory Single Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesSingle,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2315,
label: "Territory Double Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesDouble,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2316,
label: "Territory Transition Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesTransition,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2317,
label: "Territory Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesElectric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2318,
label: "Territory Non-Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(
RuntimeTerritoryMetric::TrackPiecesNonElectric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2323,
label: "Company-Territory Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::Total,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2324,
label: "Company-Territory Single Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::Single,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2325,
label: "Company-Territory Double Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::Double,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2326,
label: "Company-Territory Transition Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::Transition,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2327,
label: "Company-Territory Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::Electric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2328,
label: "Company-Territory Non-Electric Track Pieces",
kind: RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
RuntimeTrackMetric::NonElectric,
)),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID,
label: "%1 Avail.",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CARGO_PRODUCTION_CONDITION_TEMPLATE_ID,
label: "%1 Production",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
label: "Unknown Loco Available",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
label: "Unknown Loco Cost",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
label: "All Cargo Production",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_FACTORY_PRODUCTION_TOTAL_CONDITION_ID,
label: "All Factory Production",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::FactoryProductionTotal),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_FARM_MINE_PRODUCTION_TOTAL_CONDITION_ID,
label: "All Farm/Mine Production",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::FarmMineProductionTotal,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_OTHER_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
label: "Unknown Cargo Production",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::OtherCargoProductionTotal,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
label: "Limited Track Building Amount",
kind: RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
),
},
RealOrdinaryConditionMetadata {
raw_condition_id: REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
label: "Access Rights Cost:",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost),
},
RealOrdinaryConditionMetadata {
raw_condition_id: 2350,
label: "Economic Status",
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus),
},
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct KnownSpecialConditionDefinition {
slot_index: u8,
hidden: bool,
label_id: u32,
help_id: u32,
label: &'static str,
}
const KNOWN_SPECIAL_CONDITION_DEFINITIONS: [KnownSpecialConditionDefinition;
SPECIAL_CONDITION_COUNT] = [
KnownSpecialConditionDefinition {
slot_index: 0,
hidden: false,
label_id: 2535,
help_id: 2564,
label: "Disable Stock Buying and Selling",
},
KnownSpecialConditionDefinition {
slot_index: 1,
hidden: false,
label_id: 2536,
help_id: 2565,
label: "Disable Margin Buying/Short Selling Stock",
},
KnownSpecialConditionDefinition {
slot_index: 2,
hidden: false,
label_id: 2537,
help_id: 2566,
label: "Disable Company Issue/Buy Back Stock",
},
KnownSpecialConditionDefinition {
slot_index: 3,
hidden: false,
label_id: 2538,
help_id: 2567,
label: "Disable Issuing/Repaying Bonds",
},
KnownSpecialConditionDefinition {
slot_index: 4,
hidden: false,
label_id: 2539,
help_id: 2568,
label: "Disable Declaring Bankruptcy",
},
KnownSpecialConditionDefinition {
slot_index: 5,
hidden: false,
label_id: 2540,
help_id: 2569,
label: "Disable Changing the Dividend Rate",
},
KnownSpecialConditionDefinition {
slot_index: 6,
hidden: false,
label_id: 2541,
help_id: 2570,
label: "Disable Replacing a Locomotive",
},
KnownSpecialConditionDefinition {
slot_index: 7,
hidden: false,
label_id: 2542,
help_id: 2571,
label: "Disable Retiring a Train",
},
KnownSpecialConditionDefinition {
slot_index: 8,
hidden: false,
label_id: 2543,
help_id: 2572,
label: "Disable Changing Cargo Consist On Train",
},
KnownSpecialConditionDefinition {
slot_index: 9,
hidden: false,
label_id: 2544,
help_id: 2573,
label: "Disable Buying a Train",
},
KnownSpecialConditionDefinition {
slot_index: 10,
hidden: false,
label_id: 2545,
help_id: 2574,
label: "Disable All Track Building",
},
KnownSpecialConditionDefinition {
slot_index: 11,
hidden: false,
label_id: 2546,
help_id: 2575,
label: "Disable Unconnected Track Building",
},
KnownSpecialConditionDefinition {
slot_index: 12,
hidden: false,
label_id: 2547,
help_id: 2576,
label: "Limited Track Building Amount",
},
KnownSpecialConditionDefinition {
slot_index: 13,
hidden: false,
label_id: 2548,
help_id: 2577,
label: "Disable Building Stations",
},
KnownSpecialConditionDefinition {
slot_index: 14,
hidden: false,
label_id: 2549,
help_id: 2578,
label: "Disable Building Hotel/Restaurant/Tavern/Post Office",
},
KnownSpecialConditionDefinition {
slot_index: 15,
hidden: false,
label_id: 2550,
help_id: 2579,
label: "Disable Building Customs House",
},
KnownSpecialConditionDefinition {
slot_index: 16,
hidden: false,
label_id: 2551,
help_id: 2580,
label: "Disable Building Industry Buildings",
},
KnownSpecialConditionDefinition {
slot_index: 17,
hidden: false,
label_id: 2552,
help_id: 2581,
label: "Disable Buying Existing Industry Buildings",
},
KnownSpecialConditionDefinition {
slot_index: 18,
hidden: false,
label_id: 2553,
help_id: 2582,
label: "Disable Being Fired As Chairman",
},
KnownSpecialConditionDefinition {
slot_index: 19,
hidden: false,
label_id: 2554,
help_id: 2583,
label: "Disable Resigning as Chairman",
},
KnownSpecialConditionDefinition {
slot_index: 20,
hidden: false,
label_id: 2555,
help_id: 2584,
label: "Disable Chairmanship Takeover",
},
KnownSpecialConditionDefinition {
slot_index: 21,
hidden: false,
label_id: 2556,
help_id: 2585,
label: "Disable Starting Any Companies",
},
KnownSpecialConditionDefinition {
slot_index: 22,
hidden: false,
label_id: 2557,
help_id: 2586,
label: "Disable Starting Multiple Companies",
},
KnownSpecialConditionDefinition {
slot_index: 23,
hidden: false,
label_id: 2558,
help_id: 2587,
label: "Disable Merging Companies",
},
KnownSpecialConditionDefinition {
slot_index: 24,
hidden: false,
label_id: 2559,
help_id: 2588,
label: "Disable Bulldozing",
},
KnownSpecialConditionDefinition {
slot_index: 25,
hidden: false,
label_id: 2560,
help_id: 2589,
label: "Show Visited Track",
},
KnownSpecialConditionDefinition {
slot_index: 26,
hidden: false,
label_id: 2561,
help_id: 2590,
label: "Show Visited Stations",
},
KnownSpecialConditionDefinition {
slot_index: 27,
hidden: false,
label_id: 2562,
help_id: 2591,
label: "Use Slow Date",
},
KnownSpecialConditionDefinition {
slot_index: 28,
hidden: false,
label_id: 2563,
help_id: 2592,
label: "Completely Disable Money-Related Things",
},
KnownSpecialConditionDefinition {
slot_index: 29,
hidden: false,
label_id: 2874,
help_id: 2875,
label: "Use Bio-Accelerator Cars",
},
KnownSpecialConditionDefinition {
slot_index: 30,
hidden: false,
label_id: 3722,
help_id: 3723,
label: "Disable Cargo Economy",
},
KnownSpecialConditionDefinition {
slot_index: 31,
hidden: false,
label_id: 3835,
help_id: 3836,
label: "Use Wartime Cargos",
},
KnownSpecialConditionDefinition {
slot_index: 32,
hidden: false,
label_id: 3850,
help_id: 3851,
label: "Disable Train Crashes",
},
KnownSpecialConditionDefinition {
slot_index: 33,
hidden: false,
label_id: 3852,
help_id: 3853,
label: "Disable Train Crashes AND Breakdowns",
},
KnownSpecialConditionDefinition {
slot_index: 34,
hidden: false,
label_id: 3920,
help_id: 3921,
label: "AI Ignore Territories At Startup",
},
KnownSpecialConditionDefinition {
slot_index: 35,
hidden: true,
label_id: 3,
help_id: 3,
label: "Hidden sentinel",
},
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct KnownTagDefinition {
tag_id: u16,
label: &'static str,
grounded_meaning: &'static str,
}
const KNOWN_TAG_DEFINITIONS: [KnownTagDefinition; 4] = [
KnownTagDefinition {
tag_id: 0x2cee,
label: "overlay_mask_plane_primary",
grounded_meaning: "Primary one-byte overlay mask plane restored into world offset +0x1655.",
},
KnownTagDefinition {
tag_id: 0x2d51,
label: "overlay_mask_plane_secondary",
grounded_meaning: "Secondary one-byte overlay mask plane restored into world offset +0x1659.",
},
KnownTagDefinition {
tag_id: 0x9471,
label: "sidecar_byte_plane_family_low",
grounded_meaning: "Lower bound of the grounded sidecar byte-plane chunk family.",
},
KnownTagDefinition {
tag_id: 0x9472,
label: "sidecar_byte_plane_family_high",
grounded_meaning: "Upper bound of the grounded sidecar byte-plane chunk family.",
},
];
fn known_special_condition_definition_for_label_id(
label_id: u32,
) -> Option<KnownSpecialConditionDefinition> {
KNOWN_SPECIAL_CONDITION_DEFINITIONS
.iter()
.copied()
.find(|definition| !definition.hidden && definition.label_id == label_id)
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpKnownTagHit {
pub tag_id: u16,
pub tag_hex: String,
pub label: String,
pub grounded_meaning: String,
pub hit_count: usize,
pub sample_offsets: Vec<usize>,
pub last_offset: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPreambleWord {
pub index: usize,
pub offset: usize,
pub value_le: u32,
pub value_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPreamble {
pub byte_len: usize,
pub word_count: usize,
pub words: Vec<SmpPreambleWord>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpAsciiPreview {
pub offset: usize,
pub byte_len: usize,
pub preview: String,
pub truncated: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSharedHeader {
pub byte_len: usize,
pub root_kind_word: u32,
pub root_kind_word_hex: String,
pub primary_family_tag: u32,
pub primary_family_tag_hex: String,
pub shared_signature_words_1_to_7: Vec<u32>,
pub shared_signature_hex_words_1_to_7: Vec<String>,
pub matches_grounded_common_signature: bool,
pub payload_window_words_8_to_9: Vec<u32>,
pub payload_window_hex_words_8_to_9: Vec<String>,
pub reserved_words_10_to_14: Vec<u32>,
pub reserved_words_10_to_14_all_zero: bool,
pub final_flag_word: u32,
pub final_flag_word_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpHeaderVariantProbe {
pub variant_family: String,
pub variant_evidence: Vec<String>,
pub is_known_family: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpEarlyContentProbe {
pub first_post_text_nonzero_offset: usize,
pub zero_pad_after_text_len: usize,
pub first_post_text_block_len: usize,
pub first_post_text_block_hex: String,
pub trailing_zero_pad_after_first_block_len: usize,
pub secondary_nonzero_offset: Option<usize>,
pub secondary_aligned_word_window_offset: Option<usize>,
pub secondary_aligned_word_window_words: Vec<u32>,
pub secondary_aligned_word_window_hex_words: Vec<String>,
pub secondary_preview_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSecondaryVariantProbe {
pub aligned_window_offset: usize,
pub words: Vec<u32>,
pub hex_words: Vec<String>,
pub variant_family: String,
pub variant_evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpContainerProfile {
pub profile_family: String,
pub profile_evidence: Vec<String>,
pub is_known_profile: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveBootstrapBlock {
pub profile_family: String,
pub aligned_window_offset: usize,
pub leading_word: u32,
pub leading_word_hex: String,
pub anchor_word: u32,
pub anchor_word_hex: String,
pub descriptor_word_2: u32,
pub descriptor_word_2_hex: String,
pub descriptor_word_3: u32,
pub descriptor_word_3_hex: String,
pub descriptor_word_4: u32,
pub descriptor_word_4_hex: String,
pub descriptor_word_5: u32,
pub descriptor_word_5_hex: String,
pub descriptor_word_6: u32,
pub descriptor_word_6_hex: String,
pub descriptor_word_7: u32,
pub descriptor_word_7_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveAnchorRunBlock {
pub profile_family: String,
pub cycle_start_offset: usize,
pub cycle_words: Vec<u32>,
pub cycle_hex_words: Vec<String>,
pub full_cycle_count: usize,
pub partial_cycle_word_count: usize,
pub trailer_offset: usize,
pub trailer_words: Vec<u32>,
pub trailer_hex_words: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRuntimeAnchorCycleBlock {
pub profile_family: String,
pub cycle_start_offset: usize,
pub cycle_words: Vec<u32>,
pub cycle_hex_words: Vec<String>,
pub full_cycle_count: usize,
pub partial_cycle_word_count: usize,
pub trailer_offset: usize,
pub trailer_words: Vec<u32>,
pub trailer_hex_words: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRuntimeTrailerBlock {
pub profile_family: String,
pub trailer_family: String,
pub trailer_evidence: Vec<String>,
pub trailer_offset: usize,
pub prefix_words_0_to_5: Vec<u32>,
pub prefix_hex_words_0_to_5: Vec<String>,
pub tag_word_6: u32,
pub tag_word_6_hex: String,
pub tag_chunk_id_u16: u16,
pub tag_chunk_id_hex: String,
pub tag_chunk_id_grounded_alignment: Option<String>,
pub length_word_7: u32,
pub length_word_7_hex: String,
pub length_high_u16: u16,
pub length_high_hex: String,
pub selector_word_8: u32,
pub selector_word_8_hex: String,
pub selector_high_u16: u16,
pub selector_high_hex: String,
pub layout_word_9: u32,
pub layout_word_9_hex: String,
pub descriptor_word_10: u32,
pub descriptor_word_10_hex: String,
pub descriptor_high_u16: u16,
pub descriptor_high_hex: String,
pub descriptor_word_11: u32,
pub descriptor_word_11_hex: String,
pub counter_word_12: u32,
pub counter_word_12_hex: String,
pub offset_word_13: u32,
pub offset_word_13_hex: String,
pub span_word_14: u32,
pub span_word_14_hex: String,
pub mode_word_15: u32,
pub mode_word_15_hex: String,
pub words: Vec<u32>,
pub hex_words: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRuntimePostSpanProbe {
pub profile_family: String,
pub span_target_offset: usize,
pub next_nonzero_offset: Option<usize>,
pub next_aligned_candidate_offset: Option<usize>,
pub next_aligned_candidate_words: Vec<u32>,
pub next_aligned_candidate_hex_words: Vec<String>,
pub header_candidates: Vec<SmpRuntimePostSpanHeaderCandidate>,
pub grounded_progress_hits: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRuntimePostSpanHeaderCandidate {
pub offset: usize,
pub words: Vec<u32>,
pub hex_words: Vec<String>,
pub dense_word_count: usize,
pub high_u16_words: Vec<u16>,
pub high_hex_words: Vec<String>,
pub grounded_alignments: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105PostSpanBridgeProbe {
pub profile_family: String,
pub bridge_family: String,
pub bridge_evidence: Vec<String>,
pub span_target_offset: usize,
pub next_candidate_offset: Option<usize>,
pub next_candidate_delta_from_span_target: Option<usize>,
pub packed_profile_offset: usize,
pub packed_profile_delta_from_span_target: usize,
pub next_candidate_delta_from_packed_profile: Option<i64>,
pub selector_high_u16: u16,
pub selector_high_hex: String,
pub descriptor_high_u16: u16,
pub descriptor_high_hex: String,
pub next_candidate_high_u16_words: Vec<u16>,
pub next_candidate_high_hex_words: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105SaveBridgePayloadProbe {
pub profile_family: String,
pub bridge_family: String,
pub primary_block_offset: usize,
pub primary_block_len: usize,
pub primary_block_len_hex: String,
pub primary_words: Vec<u32>,
pub primary_hex_words: Vec<String>,
pub secondary_block_offset: usize,
pub secondary_block_delta_from_primary: usize,
pub secondary_block_delta_from_primary_hex: String,
pub secondary_block_end_offset: usize,
pub secondary_block_len: usize,
pub secondary_block_len_hex: String,
pub secondary_preview_word_count: usize,
pub secondary_words: Vec<u32>,
pub secondary_hex_words: Vec<String>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveWorldSelectionContextProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub chunk_tag_offset: usize,
pub payload_offset: usize,
pub payload_len: usize,
pub payload_len_hex: String,
pub selected_company_id_offset: usize,
pub selected_company_id: u32,
pub selected_company_id_hex: String,
pub selected_chairman_profile_id_offset: usize,
pub selected_chairman_profile_id: u32,
pub selected_chairman_profile_id_hex: String,
pub chairman_slot_selector_offset: usize,
pub chairman_slot_selectors: Vec<u8>,
pub campaign_override_flag_offset: usize,
pub campaign_override_flag: u8,
pub campaign_override_flag_hex: String,
pub chairman_role_gate_offset: usize,
pub chairman_role_gate_bytes: Vec<u8>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveWorldEconomicTuningProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub chunk_tag_offset: usize,
pub payload_offset: usize,
pub payload_len: usize,
pub payload_len_hex: String,
pub mirror_lane: SmpSaveDwordCandidate,
pub tuning_lanes: Vec<SmpSaveDwordCandidate>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveWorldIssue37Probe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub chunk_tag_offset: usize,
pub payload_offset: usize,
pub payload_len: usize,
pub payload_len_hex: String,
pub issue_37_raw_u8: u8,
pub issue_37_raw_hex: String,
pub issue_38_raw_u8: u8,
pub issue_38_raw_hex: String,
pub issue_39_raw_u8: u8,
pub issue_39_raw_hex: String,
pub issue_3a_raw_u8: u8,
pub issue_3a_raw_hex: String,
pub issue_value_lane: SmpSaveDwordCandidate,
pub multiplier_lane: SmpSaveDwordCandidate,
#[serde(default)]
pub issue_opinion_base_terms_raw_i32: Vec<i32>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveWorldFinanceNeighborhoodProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub chunk_tag_offset: usize,
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,
pub absolute_counter_mirror_lane: SmpSaveDwordCandidate,
pub stock_policy_raw_u8: u8,
pub stock_policy_raw_hex: String,
pub bond_policy_raw_u8: u8,
pub bond_policy_raw_hex: String,
pub bankruptcy_policy_raw_u8: u8,
pub bankruptcy_policy_raw_hex: String,
pub dividend_policy_raw_u8: u8,
pub dividend_policy_raw_hex: String,
pub building_density_growth_setting_lane: SmpSaveDwordCandidate,
pub dword_candidates: Vec<SmpSaveDwordCandidate>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveTaggedCollectionHeaderProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub metadata_tag_offset: usize,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub direct_collection_flag: u32,
pub direct_collection_flag_hex: String,
pub direct_record_stride: u32,
pub direct_record_stride_hex: String,
pub live_id_bound: u32,
pub live_id_bound_hex: String,
pub live_record_count: u32,
pub live_record_count_hex: String,
pub header_words: Vec<u32>,
pub header_hex_words: Vec<String>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveUnclassifiedTaggedCollectionHeaderProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub metadata_tag: u32,
pub metadata_tag_hex: String,
pub records_tag: u32,
pub records_tag_hex: String,
pub close_tag: u32,
pub close_tag_hex: String,
pub metadata_tag_offset: usize,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub records_span_len: usize,
pub direct_collection_flag: u32,
pub direct_collection_flag_hex: String,
pub direct_record_stride: u32,
pub direct_record_stride_hex: String,
pub live_id_bound: u32,
pub live_id_bound_hex: String,
pub live_record_count: u32,
pub live_record_count_hex: String,
pub header_words: Vec<u32>,
pub header_hex_words: Vec<String>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveTrainCollectionDirectoryEntryProbe {
pub live_entry_id: u32,
pub payload_relative_offset: u32,
pub payload_relative_offset_hex: String,
pub payload_absolute_offset: usize,
pub previous_live_entry_id: u32,
pub previous_live_entry_id_hex: String,
pub next_live_entry_id: u32,
pub next_live_entry_id_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveTrainCollectionDirectoryProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub metadata_tag_offset: usize,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub directory_root_dword_index: usize,
pub directory_entry_dword_count: usize,
pub live_record_count: u32,
pub live_id_bound: u32,
#[serde(default)]
pub chain_head_live_entry_id: Option<u32>,
#[serde(default)]
pub chain_tail_live_entry_id: Option<u32>,
pub entries: Vec<SmpSaveTrainCollectionDirectoryEntryProbe>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveRegionProfileEntryProbe {
pub entry_index: usize,
pub row_relative_offset: usize,
pub name: String,
pub trailing_weight_f32: f32,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveRegionProfileCollectionProbe {
pub direct_collection_flag: u32,
pub entry_stride: u32,
pub live_id_bound: u32,
pub live_record_count: u32,
pub entry_start_relative_offset: usize,
pub trailing_padding_len: usize,
#[serde(default)]
pub entries: Vec<SmpSaveRegionProfileEntryProbe>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveRegionRecordTripletEntryProbe {
pub record_index: usize,
pub name: String,
pub record_payload_relative_offset: usize,
pub record_payload_relative_offset_hex: String,
pub name_tag_relative_offset: usize,
pub policy_tag_relative_offset: usize,
pub profile_tag_relative_offset: usize,
pub pre_name_prefix_len: usize,
#[serde(default)]
pub pre_name_prefix_hex_bytes: Vec<String>,
#[serde(default)]
pub pre_name_prefix_dword_candidates: Vec<SmpSaveDwordCandidate>,
pub policy_chunk_len: usize,
pub profile_chunk_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<u32>,
#[serde(default)]
pub policy_reserved_dword_candidates: Vec<SmpSaveDwordCandidate>,
pub policy_trailing_word: u16,
pub policy_trailing_word_hex: String,
#[serde(default)]
pub profile_collection: Option<SmpSaveRegionProfileCollectionProbe>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveRegionRecordTripletProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub record_count: usize,
#[serde(default)]
pub entries: Vec<SmpSaveRegionRecordTripletEntryProbe>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionQueuedNoticeRecordEntryProbe {
pub node_base_offset: usize,
pub payload_seed_offset: usize,
pub next_link_raw: u32,
pub next_link_raw_hex: String,
pub payload_seed_dword: u32,
pub payload_seed_dword_hex: String,
pub kind: u32,
pub kind_hex: String,
pub promotion_latch_dword: u32,
pub promotion_latch_dword_hex: String,
pub region_id: u32,
pub region_id_hex: String,
pub amount: u32,
pub amount_hex: String,
pub trailing_sentinel_i32_0: i32,
pub trailing_sentinel_i32_0_hex: String,
pub trailing_sentinel_i32_1: i32,
pub trailing_sentinel_i32_1_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionQueuedNoticeRecordProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub payload_seed_dword: u32,
pub payload_seed_dword_hex: String,
#[serde(default)]
pub entries: Vec<SmpSaveRegionQueuedNoticeRecordEntryProbe>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveFixedRowRunDwordLaneSummary {
pub relative_offset: usize,
pub relative_offset_hex: String,
pub zero_count: usize,
pub nonzero_count: usize,
pub distinct_value_count: usize,
pub probable_normal_f32_count: usize,
pub small_unsigned_count: usize,
#[serde(default)]
pub sample_values_hex: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionFixedRowRunCandidate {
pub count_offset: usize,
pub count_offset_hex: String,
pub row_count: usize,
pub row_stride: usize,
pub row_stride_hex: String,
pub rows_offset: usize,
pub rows_offset_hex: String,
pub rows_end_offset: usize,
pub rows_end_offset_hex: String,
pub distance_to_region_metadata_tag: usize,
pub distance_to_region_metadata_tag_hex: String,
#[serde(default)]
pub dword_lane_summaries: Vec<SmpSaveFixedRowRunDwordLaneSummary>,
pub shape_signature: String,
pub shape_family_signature: String,
pub trailing_byte_zero_count: usize,
pub trailing_byte_nonzero_count: usize,
pub trailing_byte_distinct_value_count: usize,
#[serde(default)]
pub trailing_byte_sample_values_hex: Vec<String>,
#[serde(default)]
pub best_probable_density_lane_relative_offset_hex: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionFixedRowRunCandidateProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub target_row_count: usize,
pub target_row_stride: usize,
pub target_row_stride_hex: String,
pub scan_start_offset: usize,
pub scan_start_offset_hex: String,
pub scan_end_offset: usize,
pub scan_end_offset_hex: String,
#[serde(default)]
pub candidates: Vec<SmpSaveRegionFixedRowRunCandidate>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionFixedRowRunSharedShapeMatch {
pub shape_signature: String,
pub left_rank: usize,
pub left_rows_offset_hex: String,
pub left_best_probable_density_lane_relative_offset_hex: Option<String>,
pub right_rank: usize,
pub right_rows_offset_hex: String,
pub right_best_probable_density_lane_relative_offset_hex: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveRegionFixedRowRunComparisonReport {
pub left_profile_family: String,
pub right_profile_family: String,
pub left_best_rows_offset_hex: Option<String>,
pub right_best_rows_offset_hex: Option<String>,
pub left_best_shape_signature: Option<String>,
pub right_best_shape_signature: Option<String>,
pub left_best_shape_family_signature: Option<String>,
pub right_best_shape_family_signature: Option<String>,
#[serde(default)]
pub shared_shape_matches: Vec<SmpSaveRegionFixedRowRunSharedShapeMatch>,
#[serde(default)]
pub shared_shape_family_matches: Vec<SmpSaveRegionFixedRowRunSharedShapeMatch>,
#[serde(default)]
pub left_only_shape_signatures: Vec<String>,
#[serde(default)]
pub right_only_shape_signatures: Vec<String>,
#[serde(default)]
pub left_only_shape_family_signatures: Vec<String>,
#[serde(default)]
pub right_only_shape_family_signatures: Vec<String>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureRecordTripletEntryProbe {
pub record_index: usize,
pub primary_name: String,
pub secondary_name: String,
pub name_tag_relative_offset: usize,
pub policy_tag_relative_offset: usize,
pub profile_tag_relative_offset: usize,
pub policy_chunk_len: usize,
pub profile_chunk_len: usize,
pub policy_f32_lane_0: f32,
pub policy_f32_lane_1: f32,
pub policy_f32_lane_2: f32,
pub policy_f32_lane_3: f32,
pub policy_f32_lane_4: f32,
pub policy_reserved_dword: u32,
pub policy_trailing_word: u16,
pub policy_trailing_word_hex: String,
pub profile_open_marker: u32,
pub profile_open_marker_hex: String,
pub profile_repeated_primary_name: String,
pub profile_repeated_secondary_name: String,
pub profile_payload_dword: u32,
pub profile_payload_dword_hex: String,
pub profile_sentinel_i32: i32,
pub profile_status_kind: String,
pub farm_growth_stage_index: Option<u8>,
pub profile_close_marker: u32,
pub profile_close_marker_hex: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureRecordTripletProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub record_count: usize,
#[serde(default)]
pub entries: Vec<SmpSavePlacedStructureRecordTripletEntryProbe>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub metadata_tag_offset: usize,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub records_span_len: usize,
pub direct_record_stride: u32,
pub direct_record_stride_hex: String,
pub live_id_bound: u32,
pub live_id_bound_hex: String,
pub live_record_count: u32,
pub live_record_count_hex: String,
pub owner_shared_dword: u32,
pub owner_shared_dword_hex: String,
pub owner_shared_dword_relative_offset: usize,
pub owner_shared_dword_matches_first_compact_prefix_leading_dword: bool,
#[serde(default)]
pub first_record_child_count_after_owner_shared: Option<u16>,
#[serde(default)]
pub first_record_child_count_after_owner_shared_hex: Option<String>,
#[serde(default)]
pub first_record_saved_primary_child_byte_after_owner_shared: Option<u8>,
#[serde(default)]
pub first_record_saved_primary_child_byte_after_owner_shared_hex: Option<String>,
#[serde(default)]
pub first_record_first_name_tag_relative_offset_after_owner_shared: Option<usize>,
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub first_embedded_name_tag_relative_offset: usize,
pub embedded_name_tag_count: usize,
pub decoded_embedded_name_row_count: usize,
pub decoded_embedded_name_row_with_tertiary_name_count: usize,
pub unique_compact_prefix_pattern_count: usize,
pub prefix_leading_dword_matching_embedded_profile_tag_count: usize,
pub unique_embedded_name_pair_count: usize,
#[serde(default)]
pub first_embedded_primary_name: Option<String>,
#[serde(default)]
pub first_embedded_secondary_name: Option<String>,
#[serde(default)]
pub first_embedded_tertiary_name: Option<String>,
#[serde(default)]
pub embedded_name_row_samples: Vec<SmpSavePlacedStructureDynamicSideBufferSampleEntry>,
#[serde(default)]
pub compact_prefix_pattern_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary>,
#[serde(default)]
pub name_pair_summaries: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
#[serde(default)]
pub payload_envelope_summary:
Option<SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary>,
#[serde(default)]
pub live_entry_prelude_summary:
Option<SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSummary>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferSampleEntry {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
#[serde(default)]
pub tertiary_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary {
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub count: usize,
pub first_name_tag_relative_offset: usize,
pub prefix_leading_dword_matches_embedded_profile_tag: bool,
pub section_like_primary_name_count: usize,
pub cap_like_primary_name_count: usize,
pub other_primary_name_count: usize,
#[serde(default)]
pub first_primary_name: Option<String>,
#[serde(default)]
pub first_secondary_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
pub primary_name: String,
pub secondary_name: String,
pub count: usize,
pub first_name_tag_relative_offset: usize,
pub unique_compact_prefix_pattern_count: usize,
pub dominant_prefix_leading_dword: u32,
pub dominant_prefix_leading_dword_hex: String,
pub dominant_prefix_trailing_word: u16,
pub dominant_prefix_trailing_word_hex: String,
pub dominant_prefix_separator_byte: u8,
pub dominant_prefix_separator_byte_hex: String,
pub dominant_prefix_count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
pub row_count_with_policy_tag_before_next_name: usize,
pub row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope: usize,
pub row_count_missing_policy_tag_before_next_name: usize,
pub row_count_missing_profile_tag_after_policy: usize,
#[serde(default)]
pub unique_policy_chunk_lens: Vec<usize>,
#[serde(default)]
pub unique_profile_chunk_lens: Vec<usize>,
#[serde(default)]
pub dominant_policy_chunk_len: Option<usize>,
pub dominant_policy_chunk_len_count: usize,
#[serde(default)]
pub dominant_profile_chunk_len: Option<usize>,
pub dominant_profile_chunk_len_count: usize,
#[serde(default)]
pub short_profile_flag_pair_summary:
Option<SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSummary>,
#[serde(default)]
pub fixed_policy_summary: Option<SmpSavePlacedStructureDynamicSideBufferFixedPolicySummary>,
#[serde(default)]
pub name_prelude_candidate_summary:
Option<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSummary>,
#[serde(default)]
pub dominant_profile_span_class_summary:
Option<SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanClassSummary>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanClassSummary {
pub profile_chunk_len_to_next_name_or_end: usize,
pub row_count: usize,
pub unique_name_pair_count: usize,
pub unique_compact_prefix_pattern_count: usize,
#[serde(default)]
pub dominant_candidate_pattern:
Option<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern>,
#[serde(default)]
pub dominant_primary_name: Option<String>,
#[serde(default)]
pub dominant_secondary_name: Option<String>,
pub dominant_name_pair_count: usize,
#[serde(default)]
pub dominant_prefix_leading_dword: Option<u32>,
#[serde(default)]
pub dominant_prefix_leading_dword_hex: Option<String>,
#[serde(default)]
pub dominant_prefix_trailing_word: Option<u16>,
#[serde(default)]
pub dominant_prefix_trailing_word_hex: Option<String>,
#[serde(default)]
pub dominant_prefix_separator_byte: Option<u8>,
#[serde(default)]
pub dominant_prefix_separator_byte_hex: Option<String>,
pub dominant_prefix_count: usize,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanSample>,
#[serde(default)]
pub name_pair_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary>,
#[serde(default)]
pub compact_prefix_pattern_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanPrefixSummary>,
#[serde(default)]
pub candidate_pattern_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
#[serde(default)]
pub child_count_candidate: Option<u16>,
#[serde(default)]
pub child_count_candidate_hex: Option<String>,
#[serde(default)]
pub saved_primary_child_byte_candidate: Option<u8>,
#[serde(default)]
pub saved_primary_child_byte_candidate_hex: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanPrefixSummary {
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferFixedPolicySummary {
pub row_count_with_0x1a_policy_chunk: usize,
pub unique_trailing_word_count: usize,
#[serde(default)]
pub dominant_trailing_word: Option<u16>,
#[serde(default)]
pub dominant_trailing_word_hex: Option<String>,
pub dominant_trailing_word_count: usize,
#[serde(default)]
pub compact_prefix_correlations:
Vec<SmpSavePlacedStructureDynamicSideBufferFixedPolicyCompactPrefixCorrelation>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferFixedPolicySample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferFixedPolicySample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
#[serde(default)]
pub first_triplet_dwords_hex: Vec<String>,
#[serde(default)]
pub second_triplet_dwords_hex: Vec<String>,
pub trailing_word: u16,
pub trailing_word_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferFixedPolicyCompactPrefixCorrelation {
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub row_count: usize,
pub unique_policy_tuple_count: usize,
#[serde(default)]
pub dominant_primary_name: Option<String>,
#[serde(default)]
pub dominant_secondary_name: Option<String>,
pub dominant_name_pair_count: usize,
#[serde(default)]
pub dominant_mode_family: Option<String>,
pub dominant_mode_family_count: usize,
#[serde(default)]
pub dominant_first_triplet_dwords_hex: Vec<String>,
#[serde(default)]
pub dominant_second_triplet_dwords_hex: Vec<String>,
#[serde(default)]
pub dominant_trailing_word: Option<u16>,
#[serde(default)]
pub dominant_trailing_word_hex: Option<String>,
pub dominant_policy_tuple_count: usize,
#[serde(default)]
pub mode_family_counts: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferFixedPolicySample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSummary {
pub row_count_with_0x06_profile_span: usize,
pub unique_flag_pair_count: usize,
#[serde(default)]
pub dominant_first_flag_byte: Option<u8>,
#[serde(default)]
pub dominant_first_flag_byte_hex: Option<String>,
pub dominant_first_flag_byte_count: usize,
#[serde(default)]
pub dominant_second_flag_byte: Option<u8>,
#[serde(default)]
pub dominant_second_flag_byte_hex: Option<String>,
pub dominant_second_flag_byte_count: usize,
#[serde(default)]
pub dominant_flag_pair: Option<SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPair>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPair {
pub first_flag_byte: u8,
pub first_flag_byte_hex: String,
pub second_flag_byte: u8,
pub second_flag_byte_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub first_flag_byte: u8,
pub first_flag_byte_hex: String,
pub second_flag_byte: u8,
pub second_flag_byte_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
#[serde(default)]
pub name_payload_end_relative_offset: Option<usize>,
#[serde(default)]
pub policy_tag_relative_offset: Option<usize>,
#[serde(default)]
pub profile_tag_relative_offset: Option<usize>,
#[serde(default)]
pub next_name_tag_relative_offset: Option<usize>,
#[serde(default)]
pub name_to_policy_gap_len: Option<usize>,
#[serde(default)]
pub policy_chunk_len: Option<usize>,
#[serde(default)]
pub profile_chunk_len_to_next_name_or_end: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSummary {
pub row_count_with_candidate_window: usize,
pub unique_candidate_pattern_count: usize,
#[serde(default)]
pub dominant_child_count_candidate: Option<u16>,
pub dominant_child_count_candidate_count: usize,
#[serde(default)]
pub dominant_saved_primary_child_byte_candidate: Option<u8>,
#[serde(default)]
pub dominant_saved_primary_child_byte_candidate_hex: Option<String>,
pub dominant_saved_primary_child_byte_candidate_count: usize,
#[serde(default)]
pub dominant_candidate_pattern:
Option<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern>,
#[serde(default)]
pub candidate_pattern_correlations:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePatternCorrelation>,
#[serde(default)]
pub profile_span_correlations:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation>,
#[serde(default)]
pub compact_prefix_correlations:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
pub child_count_candidate: u16,
pub child_count_candidate_hex: String,
pub saved_primary_child_byte_candidate: u8,
pub saved_primary_child_byte_candidate_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub child_count_candidate: u16,
pub child_count_candidate_hex: String,
pub saved_primary_child_byte_candidate: u8,
pub saved_primary_child_byte_candidate_hex: String,
#[serde(default)]
pub previous_profile_chunk_len_to_next_name_or_end: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation {
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub row_count: usize,
pub unique_name_pair_count: usize,
pub unique_profile_span_count: usize,
#[serde(default)]
pub dominant_primary_name: Option<String>,
#[serde(default)]
pub dominant_secondary_name: Option<String>,
pub dominant_name_pair_count: usize,
#[serde(default)]
pub dominant_profile_span: Option<usize>,
pub dominant_profile_span_count: usize,
#[serde(default)]
pub dominant_candidate_pattern:
Option<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern>,
#[serde(default)]
pub dominant_mode_family: Option<String>,
pub dominant_mode_family_count: usize,
#[serde(default)]
pub mode_family_counts: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount>,
#[serde(default)]
pub name_pair_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary>,
#[serde(default)]
pub profile_span_counts:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount>,
pub rows_with_previous_short_profile_flag_pair: usize,
#[serde(default)]
pub previous_short_profile_flag_pair_counts:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount {
pub previous_profile_chunk_len_to_next_name_or_end: usize,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount {
pub first_flag_byte: u8,
pub first_flag_byte_hex: String,
pub second_flag_byte: u8,
pub second_flag_byte_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub child_count_candidate: u16,
pub child_count_candidate_hex: String,
pub saved_primary_child_byte_candidate: u8,
pub saved_primary_child_byte_candidate_hex: String,
#[serde(default)]
pub previous_profile_chunk_len_to_next_name_or_end: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePatternCorrelation {
pub child_count_candidate: u16,
pub child_count_candidate_hex: String,
pub saved_primary_child_byte_candidate: u8,
pub saved_primary_child_byte_candidate_hex: String,
pub row_count: usize,
pub unique_name_pair_count: usize,
pub unique_profile_span_count: usize,
#[serde(default)]
pub dominant_primary_name: Option<String>,
#[serde(default)]
pub dominant_secondary_name: Option<String>,
pub dominant_name_pair_count: usize,
#[serde(default)]
pub dominant_profile_span: Option<usize>,
pub dominant_profile_span_count: usize,
#[serde(default)]
pub dominant_mode_family: Option<String>,
pub dominant_mode_family_count: usize,
#[serde(default)]
pub mode_family_counts: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
pub mode_family: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
pub previous_profile_chunk_len_to_next_name_or_end: usize,
pub row_count: usize,
#[serde(default)]
pub dominant_child_count_candidate: Option<u16>,
pub dominant_child_count_candidate_count: usize,
#[serde(default)]
pub dominant_saved_primary_child_byte_candidate: Option<u8>,
#[serde(default)]
pub dominant_saved_primary_child_byte_candidate_hex: Option<String>,
pub dominant_saved_primary_child_byte_candidate_count: usize,
#[serde(default)]
pub dominant_candidate_pattern:
Option<SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern>,
#[serde(default)]
pub dominant_mode_family: Option<String>,
pub dominant_mode_family_count: usize,
#[serde(default)]
pub mode_family_counts: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount>,
#[serde(default)]
pub compact_prefix_pattern_summaries:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary>,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub count: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
pub sample_index: usize,
pub name_tag_relative_offset: usize,
#[serde(default)]
pub primary_name: Option<String>,
#[serde(default)]
pub secondary_name: Option<String>,
pub prefix_leading_dword: u32,
pub prefix_leading_dword_hex: String,
pub prefix_trailing_word: u16,
pub prefix_trailing_word_hex: String,
pub prefix_separator_byte: u8,
pub prefix_separator_byte_hex: String,
pub child_count_candidate: u16,
pub child_count_candidate_hex: String,
pub saved_primary_child_byte_candidate: u8,
pub saved_primary_child_byte_candidate_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSummary {
pub live_entry_directory_row_count: usize,
pub decoded_live_entry_id_count: usize,
pub payload_relative_offset_monotonic: bool,
pub rows_with_payload_pointer_inside_records_span: usize,
pub rows_with_zero_child_count: usize,
pub rows_with_nonzero_child_count: usize,
pub rows_with_first_name_tag_after_prelude: usize,
pub rows_with_first_name_tag_at_offset_3: usize,
#[serde(default)]
pub unique_child_count_values: Vec<u16>,
#[serde(default)]
pub unique_first_name_tag_relative_offsets: Vec<usize>,
#[serde(default)]
pub dominant_child_count: Option<u16>,
pub dominant_child_count_count: usize,
#[serde(default)]
pub dominant_saved_primary_child_byte: Option<u8>,
#[serde(default)]
pub dominant_saved_primary_child_byte_hex: Option<String>,
pub dominant_saved_primary_child_byte_count: usize,
#[serde(default)]
pub dominant_first_name_tag_relative_offset: Option<usize>,
pub dominant_first_name_tag_relative_offset_count: usize,
#[serde(default)]
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSample>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSample {
pub sample_index: usize,
pub live_entry_id: u32,
pub payload_relative_offset: u32,
pub payload_relative_offset_hex: String,
pub payload_relative_to_records: usize,
pub child_count: u16,
pub child_count_hex: String,
pub saved_primary_child_byte: u8,
pub saved_primary_child_byte_hex: String,
pub first_payload_dword_hex: String,
#[serde(default)]
pub first_name_tag_relative_offset: Option<usize>,
#[serde(default)]
pub first_primary_name: Option<String>,
#[serde(default)]
pub first_secondary_name: Option<String>,
#[serde(default)]
pub first_tertiary_name: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
pub unique_side_buffer_name_pair_count: usize,
pub unique_triplet_name_pair_count: usize,
pub overlapping_name_pair_count: usize,
pub side_buffer_row_count: usize,
pub side_buffer_rows_with_matching_triplet_name_pair_count: usize,
pub side_buffer_rows_without_matching_triplet_name_pair_count: usize,
pub triplet_name_pairs_without_side_buffer_match_count: usize,
#[serde(default)]
pub matched_name_pair_samples: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
#[serde(default)]
pub unmatched_side_buffer_name_pair_samples:
Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105SaveNameTableProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub semantic_alignment: Vec<String>,
pub header_offset: usize,
pub header_word_0: u32,
pub header_word_0_hex: String,
pub header_word_1: u32,
pub header_word_1_hex: String,
pub header_word_2: u32,
pub header_word_2_hex: String,
pub entry_stride: usize,
pub entry_stride_hex: String,
pub header_prefix_word_count: usize,
pub observed_entry_capacity: usize,
pub observed_entry_count: usize,
pub zero_trailer_entry_count: usize,
pub nonzero_trailer_entry_count: usize,
pub distinct_trailer_words: Vec<u32>,
pub distinct_trailer_hex_words: Vec<String>,
pub zero_trailer_entry_names: Vec<String>,
pub entries_offset: usize,
pub entries_end_offset: usize,
pub trailing_footer_hex: String,
pub footer_progress_word_0: u32,
pub footer_progress_word_0_hex: String,
pub footer_progress_word_1: u32,
pub footer_progress_word_1_hex: String,
pub footer_trailing_byte: u8,
pub footer_trailing_byte_hex: String,
pub footer_grounded_alignments: Vec<String>,
pub entries: Vec<SmpRt3105SaveNameTableEntry>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105SaveNamedLocomotiveAvailabilityProbe {
pub profile_family: String,
pub source_kind: String,
pub semantic_family: String,
pub semantic_alignment: Vec<String>,
pub entries_offset: usize,
pub entry_stride: usize,
pub entry_stride_hex: String,
pub observed_entry_count: usize,
pub zero_availability_count: usize,
pub zero_availability_names: Vec<String>,
pub entries_end_offset: usize,
pub entries: Vec<SmpRt3105SaveNameTableEntry>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105SaveNameTableEntry {
pub index: usize,
pub offset: usize,
pub text: String,
pub availability_dword: u32,
pub availability_dword_hex: String,
pub trailer_word: u32,
pub trailer_word_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSpecialConditionEntry {
pub slot_index: u8,
pub hidden: bool,
pub label_id: u32,
pub help_id: u32,
pub label: String,
pub value: u32,
pub value_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSpecialConditionsProbe {
pub profile_family: String,
pub source_kind: String,
pub table_offset: usize,
pub table_len: usize,
pub enabled_visible_count: usize,
pub enabled_visible_labels: Vec<String>,
pub hidden_sentinel_slot_index: u8,
pub hidden_sentinel_value: u32,
pub hidden_sentinel_value_hex: String,
pub entries: Vec<SmpSpecialConditionEntry>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpAlignedRuntimeRuleBandLane {
pub band_index: usize,
pub absolute_offset: usize,
pub relative_offset: usize,
pub absolute_offset_hex: String,
pub relative_offset_hex: String,
pub lane_kind: String,
pub known_label: Option<String>,
pub value: u32,
pub value_hex: String,
pub probable_f32_le: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpAlignedRuntimeRuleBandProbe {
pub profile_family: String,
pub source_kind: String,
pub band_offset: usize,
pub band_end_offset: usize,
pub band_len: usize,
pub band_len_hex: String,
pub dword_count: usize,
pub known_editor_rule_dword_count: usize,
pub trailing_scalar_index: usize,
pub trailing_scalar_offset: usize,
pub trailing_scalar_offset_hex: String,
pub post_window_overlap_start_index: usize,
pub post_window_overlap_dword_count: usize,
pub post_window_overlap_end_index: usize,
pub post_window_overlap_post_relative_offset_start_hex: String,
pub post_window_overlap_post_relative_offset_end_hex: String,
pub nonzero_post_window_overlap_band_indices: Vec<usize>,
pub nonzero_post_window_overlap_post_relative_offset_hexes: Vec<String>,
pub nonzero_lane_count: usize,
pub nonzero_band_indices: Vec<usize>,
pub nonzero_relative_offset_hexes: Vec<String>,
pub nonzero_lanes: Vec<SmpAlignedRuntimeRuleBandLane>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPostSpecialConditionsScalarLane {
pub absolute_offset: usize,
pub relative_offset: usize,
pub absolute_offset_hex: String,
pub relative_offset_hex: String,
pub value: u32,
pub value_hex: String,
pub probable_f32_le: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPostTextGroundedFieldObservation {
pub field_name: String,
pub runtime_object_offset: usize,
pub runtime_object_offset_hex: String,
pub file_offset: usize,
pub file_offset_hex: String,
pub field_width_bytes: usize,
pub field_width_bytes_hex: String,
pub raw_hex: String,
pub value_u8: Option<u8>,
pub value_u8_hex: Option<String>,
pub value_u32: Option<u32>,
pub value_u32_hex: Option<String>,
pub probable_f32_le: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPostTextFloatAlignmentCandidate {
pub grounded_field_name: String,
pub grounded_field_runtime_object_offset: usize,
pub grounded_field_runtime_object_offset_hex: String,
pub grounded_field_file_offset: usize,
pub grounded_field_file_offset_hex: String,
pub candidate_offset: usize,
pub candidate_offset_hex: String,
pub candidate_value: u32,
pub candidate_value_hex: String,
pub probable_f32_le: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPostTextFieldNeighborhoodProbe {
pub profile_family: String,
pub source_kind: String,
pub window_offset: usize,
pub window_end_offset: usize,
pub window_len: usize,
pub window_len_hex: String,
pub grounded_field_observations: Vec<SmpPostTextGroundedFieldObservation>,
pub one_byte_early_float_candidates: Vec<SmpPostTextFloatAlignmentCandidate>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLocomotivePolicyFieldObservation {
pub field_name: String,
pub runtime_object_offset: usize,
pub runtime_object_offset_hex: String,
pub file_offset: usize,
pub file_offset_hex: String,
pub field_width_bytes: usize,
pub field_width_bytes_hex: String,
pub raw_hex: String,
pub value_u8: Option<u8>,
pub value_u8_hex: Option<String>,
pub value_u32: Option<u32>,
pub value_u32_hex: Option<String>,
pub probable_f32_le: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLocomotivePolicyFloatAlignmentCandidate {
pub grounded_field_name: String,
pub grounded_field_runtime_object_offset: usize,
pub grounded_field_runtime_object_offset_hex: String,
pub grounded_field_file_offset: usize,
pub grounded_field_file_offset_hex: String,
pub candidate_offset: usize,
pub candidate_offset_hex: String,
pub candidate_value: u32,
pub candidate_value_hex: String,
pub probable_f32_le: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLocomotivePolicyNeighborhoodProbe {
pub profile_family: String,
pub source_kind: String,
pub window_offset: usize,
pub window_end_offset: usize,
pub window_len: usize,
pub window_len_hex: String,
pub grounded_field_observations: Vec<SmpLocomotivePolicyFieldObservation>,
pub three_byte_early_float_candidates: Vec<SmpLocomotivePolicyFloatAlignmentCandidate>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPreRecipeScalarPlateauLane {
pub absolute_offset: usize,
pub relative_offset: usize,
pub absolute_offset_hex: String,
pub relative_offset_hex: String,
pub value: u32,
pub value_hex: String,
pub probable_f32_le: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPreRecipeScalarPlateauProbe {
pub profile_family: String,
pub source_kind: String,
pub window_offset: usize,
pub window_end_offset: usize,
pub window_len: usize,
pub window_len_hex: String,
pub aligned_dword_count: usize,
pub family_signature: String,
pub nonzero_lanes: Vec<SmpPreRecipeScalarPlateauLane>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRecipeBookSummaryBook {
pub book_index: usize,
pub book_offset: usize,
pub book_offset_hex: String,
pub head_kind: String,
pub head_nonzero_byte_count: usize,
pub head_cdcd_byte_count: usize,
pub head_first_16_hex: String,
pub max_annual_production_offset: usize,
pub max_annual_production_offset_hex: String,
pub max_annual_production_word: u32,
pub max_annual_production_word_hex: String,
pub max_annual_production_probable_f32_le: Option<String>,
pub line_area_offset: usize,
pub line_area_offset_hex: String,
pub line_area_len: usize,
pub line_area_len_hex: String,
pub line_area_kind: String,
pub line_area_nonzero_byte_count: usize,
pub line_area_cdcd_byte_count: usize,
pub line_area_first_16_hex: String,
pub lines: Vec<SmpRecipeBookLineSummary>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRecipeBookLineSummary {
pub line_index: usize,
pub line_offset: usize,
pub line_offset_hex: String,
pub line_kind: String,
pub line_signature_kind: String,
pub imports_to_runtime_descriptor: bool,
pub runtime_import_branch_kind: String,
pub line_nonzero_byte_count: usize,
pub line_cdcd_byte_count: usize,
pub line_first_16_hex: String,
pub mode_word_offset: usize,
pub mode_word_offset_hex: String,
pub mode_word: u32,
pub mode_word_hex: String,
pub annual_amount_offset: usize,
pub annual_amount_offset_hex: String,
pub annual_amount_word: u32,
pub annual_amount_word_hex: String,
pub annual_amount_probable_f32_le: Option<String>,
pub supplied_cargo_token_offset: usize,
pub supplied_cargo_token_offset_hex: String,
pub supplied_cargo_token_word: u32,
pub supplied_cargo_token_word_hex: String,
pub supplied_cargo_token_layout_kind: String,
pub supplied_cargo_token_window_hex: String,
pub supplied_cargo_token_window_ascii: String,
pub supplied_cargo_token_active_in_runtime_import: bool,
pub supplied_cargo_token_probable_high16_ascii_stem: Option<String>,
pub demanded_cargo_token_offset: usize,
pub demanded_cargo_token_offset_hex: String,
pub demanded_cargo_token_word: u32,
pub demanded_cargo_token_word_hex: String,
pub demanded_cargo_token_layout_kind: String,
pub demanded_cargo_token_window_hex: String,
pub demanded_cargo_token_window_ascii: String,
pub demanded_cargo_token_active_in_runtime_import: bool,
pub demanded_cargo_token_probable_high16_ascii_stem: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRecipeBookSummaryProbe {
pub profile_family: String,
pub source_kind: String,
pub root_offset: usize,
pub root_offset_hex: String,
pub runtime_object_root_offset: usize,
pub runtime_object_root_offset_hex: String,
pub book_count: usize,
pub book_stride: usize,
pub book_stride_hex: String,
pub max_annual_production_relative_offset: usize,
pub max_annual_production_relative_offset_hex: String,
pub line_area_relative_offset: usize,
pub line_area_relative_offset_hex: String,
pub line_count: usize,
pub line_stride: usize,
pub line_stride_hex: String,
pub books: Vec<SmpRecipeBookSummaryBook>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPostSpecialConditionsScalarProbe {
pub profile_family: String,
pub source_kind: String,
pub window_offset: usize,
pub window_end_offset: usize,
pub window_len: usize,
pub window_len_hex: String,
pub dword_count: usize,
pub overlap_end_offset: usize,
pub overlap_end_offset_hex: String,
pub overlap_dword_count: usize,
pub overlap_nonzero_dword_count: usize,
pub overlap_nonzero_relative_offset_hexes: Vec<String>,
pub tail_offset: usize,
pub tail_offset_hex: String,
pub tail_len: usize,
pub tail_len_hex: String,
pub tail_dword_count: usize,
pub tail_runtime_object_offset: usize,
pub tail_runtime_object_offset_hex: String,
pub tail_runtime_object_end_offset: usize,
pub tail_runtime_object_end_offset_hex: String,
pub tail_runtime_object_validated_byte_mirror: bool,
pub tail_grounded_live_field_offset: usize,
pub tail_grounded_live_field_offset_hex: String,
pub tail_grounded_live_field_name: String,
pub tail_grounded_live_field_copy_len: usize,
pub tail_grounded_live_field_copy_len_hex: String,
pub tail_grounded_live_field_copy_end_offset: usize,
pub tail_grounded_live_field_copy_end_offset_hex: String,
pub tail_window_cuts_through_grounded_live_field: bool,
pub tail_grounded_live_field_remaining_file_window_offset: usize,
pub tail_grounded_live_field_remaining_file_window_offset_hex: String,
pub tail_grounded_live_field_remaining_file_window_len: usize,
pub tail_grounded_live_field_remaining_file_window_len_hex: String,
pub tail_grounded_live_field_remaining_file_window_nonzero_byte_count: usize,
pub tail_grounded_live_field_remaining_file_window_first_nonzero_offset: Option<usize>,
pub tail_grounded_live_field_remaining_file_window_first_nonzero_offset_hex: Option<String>,
pub tail_grounded_live_field_remaining_file_window_last_nonzero_offset: Option<usize>,
pub tail_grounded_live_field_remaining_file_window_last_nonzero_offset_hex: Option<String>,
pub tail_next_grounded_dword_field_offset: usize,
pub tail_next_grounded_dword_field_offset_hex: String,
pub tail_next_grounded_dword_field_file_offset: usize,
pub tail_next_grounded_dword_field_file_offset_hex: String,
pub tail_second_grounded_dword_field_offset: usize,
pub tail_second_grounded_dword_field_offset_hex: String,
pub tail_second_grounded_dword_field_file_offset: usize,
pub tail_second_grounded_dword_field_file_offset_hex: String,
pub post_text_field_file_alignment_matches_grounded_dword_fields: bool,
pub tail_nonzero_dword_count: usize,
pub tail_first_nonzero_offset: Option<usize>,
pub tail_first_nonzero_offset_hex: Option<String>,
pub tail_last_nonzero_offset: Option<usize>,
pub tail_last_nonzero_offset_hex: Option<String>,
pub tail_nonzero_relative_offset_hexes: Vec<String>,
pub nonzero_dword_count: usize,
pub first_nonzero_offset: Option<usize>,
pub first_nonzero_offset_hex: Option<String>,
pub last_nonzero_offset: Option<usize>,
pub last_nonzero_offset_hex: Option<String>,
pub nonzero_lanes: Vec<SmpPostSpecialConditionsScalarLane>,
pub evidence: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpClassicRehydrateProfileProbe {
pub profile_family: String,
pub progress_32dc_offset: usize,
pub progress_3714_offset: usize,
pub progress_3715_offset: usize,
pub packed_profile_offset: usize,
pub packed_profile_len: usize,
pub packed_profile_len_hex: String,
pub packed_profile_block: SmpClassicPackedProfileBlock,
pub ascii_runs: Vec<SmpAsciiPreview>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpClassicPackedProfileBlock {
pub relative_len: usize,
pub relative_len_hex: String,
pub leading_word_0: u32,
pub leading_word_0_hex: String,
pub trailing_zero_word_count_after_leading_word: usize,
pub map_path_offset: usize,
pub map_path: Option<String>,
pub display_name_offset: usize,
pub display_name: Option<String>,
pub profile_byte_0x77: u8,
pub profile_byte_0x77_hex: String,
pub profile_byte_0x82: u8,
pub profile_byte_0x82_hex: String,
pub profile_byte_0x97: u8,
pub profile_byte_0x97_hex: String,
pub profile_byte_0xc5: u8,
pub profile_byte_0xc5_hex: String,
pub stable_nonzero_words: Vec<SmpPackedProfileWordLane>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105PackedProfileProbe {
pub profile_family: String,
pub packed_profile_offset: usize,
pub packed_profile_len: usize,
pub packed_profile_len_hex: String,
pub packed_profile_block: SmpRt3105PackedProfileBlock,
pub ascii_runs: Vec<SmpAsciiPreview>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRt3105PackedProfileBlock {
pub relative_len: usize,
pub relative_len_hex: String,
pub leading_word_0: u32,
pub leading_word_0_hex: String,
pub trailing_zero_word_count_after_leading_word: usize,
pub header_flag_word_3: u32,
pub header_flag_word_3_hex: String,
pub map_path_offset: usize,
pub map_path: Option<String>,
pub display_name_offset: usize,
pub display_name: Option<String>,
pub profile_byte_0x77: u8,
pub profile_byte_0x77_hex: String,
pub profile_byte_0x82: u8,
pub profile_byte_0x82_hex: String,
pub profile_byte_0x97: u8,
pub profile_byte_0x97_hex: String,
pub profile_byte_0xc5: u8,
pub profile_byte_0xc5_hex: String,
pub stable_nonzero_words: Vec<SmpPackedProfileWordLane>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveLoadCandidateTableSummary {
pub source_kind: String,
pub semantic_family: String,
pub observed_entry_count: usize,
pub zero_availability_count: usize,
pub zero_availability_names: Vec<String>,
pub footer_progress_hex_words: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveLoadSummary {
pub file_extension_hint: Option<String>,
pub container_profile_family: Option<String>,
pub mechanism_family: String,
pub mechanism_confidence: String,
pub packed_profile_kind: Option<String>,
pub packed_profile_family: Option<String>,
pub packed_profile_offset: Option<usize>,
pub packed_profile_len: Option<usize>,
pub map_path: Option<String>,
pub display_name: Option<String>,
pub profile_byte_0x77: Option<u8>,
pub profile_byte_0x77_hex: Option<String>,
pub profile_byte_0x82: Option<u8>,
pub profile_byte_0x82_hex: Option<String>,
pub profile_byte_0x97: Option<u8>,
pub profile_byte_0x97_hex: Option<String>,
pub profile_byte_0xc5: Option<u8>,
pub profile_byte_0xc5_hex: Option<String>,
pub trailer_family: Option<String>,
pub bridge_family: Option<String>,
pub candidate_table: Option<SmpSaveLoadCandidateTableSummary>,
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedProfile {
pub profile_kind: String,
pub profile_family: String,
pub packed_profile_offset: usize,
pub packed_profile_len: usize,
pub packed_profile_len_hex: String,
pub leading_word_0: u32,
pub leading_word_0_hex: String,
pub header_flag_word_3: Option<u32>,
pub header_flag_word_3_hex: Option<String>,
pub map_path: Option<String>,
pub display_name: Option<String>,
pub profile_byte_0x77: u8,
pub profile_byte_0x77_hex: String,
pub profile_byte_0x82: u8,
pub profile_byte_0x82_hex: String,
pub profile_byte_0x97: u8,
pub profile_byte_0x97_hex: String,
pub profile_byte_0xc5: u8,
pub profile_byte_0xc5_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCandidateAvailabilityTable {
pub source_kind: String,
pub semantic_family: String,
pub header_offset: usize,
pub entries_offset: usize,
pub entries_end_offset: usize,
pub observed_entry_count: usize,
pub zero_availability_count: usize,
pub zero_availability_names: Vec<String>,
pub footer_progress_hex_words: Vec<String>,
pub entries: Vec<SmpRt3105SaveNameTableEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedNamedLocomotiveAvailabilityTable {
pub source_kind: String,
pub semantic_family: String,
#[serde(default)]
pub header_offset: Option<usize>,
#[serde(default)]
pub entries_offset: Option<usize>,
#[serde(default)]
pub entries_end_offset: Option<usize>,
pub observed_entry_count: usize,
pub zero_availability_count: usize,
pub zero_availability_names: Vec<String>,
pub entries: Vec<SmpRt3105SaveNameTableEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedLocomotiveCatalogEntry {
pub locomotive_id: u32,
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedLocomotiveCatalog {
pub source_kind: String,
pub semantic_family: String,
#[serde(default)]
pub entries_offset: Option<usize>,
pub observed_entry_count: usize,
pub entries: Vec<SmpLoadedLocomotiveCatalogEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCargoCatalogEntry {
pub slot_id: u32,
pub label: String,
#[serde(default)]
pub cargo_class: RuntimeCargoClass,
pub book_index: usize,
pub max_annual_production_word: u32,
pub mode_word: u32,
pub runtime_import_branch_kind: String,
pub annual_amount_word: u32,
pub supplied_cargo_token_word: u32,
#[serde(default)]
pub supplied_cargo_token_probable_high16_ascii_stem: Option<String>,
pub demanded_cargo_token_word: u32,
#[serde(default)]
pub demanded_cargo_token_probable_high16_ascii_stem: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCargoCatalog {
pub source_kind: String,
pub semantic_family: String,
#[serde(default)]
pub root_offset: Option<usize>,
pub observed_entry_count: usize,
pub entries: Vec<SmpLoadedCargoCatalogEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedWorldIssue37State {
pub source_kind: String,
pub semantic_family: String,
pub issue_value: u32,
pub issue_value_hex: String,
pub issue_38_value: u32,
pub issue_38_value_hex: String,
pub issue_39_value: u32,
pub issue_39_value_hex: String,
pub issue_3a_value: u32,
pub issue_3a_value_hex: String,
pub multiplier_raw_u32: u32,
pub multiplier_raw_hex: String,
pub multiplier_value_f32_text: String,
#[serde(default)]
pub issue_opinion_base_terms_raw_i32: Vec<i32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedWorldEconomicTuningState {
pub source_kind: String,
pub semantic_family: String,
pub mirror_raw_u32: u32,
pub mirror_raw_hex: String,
pub mirror_value_f32_text: String,
pub lane_raw_u32: Vec<u32>,
pub lane_raw_hex: Vec<String>,
pub lane_value_f32_text: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
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,
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 stock_policy_raw_u8: u8,
pub stock_policy_raw_hex: String,
pub bond_policy_raw_u8: u8,
pub bond_policy_raw_hex: String,
pub bankruptcy_policy_raw_u8: u8,
pub bankruptcy_policy_raw_hex: String,
pub dividend_policy_raw_u8: u8,
pub dividend_policy_raw_hex: String,
pub building_density_growth_setting_raw_u32: u32,
pub building_density_growth_setting_raw_hex: String,
pub labels: Vec<String>,
pub relative_offsets: Vec<usize>,
pub relative_offset_hex: Vec<String>,
pub raw_u32: Vec<u32>,
pub raw_hex: Vec<String>,
pub value_i32: Vec<i32>,
pub value_f32_text: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedWorldLocomotivePolicyState {
pub source_kind: String,
pub semantic_family: String,
#[serde(default)]
pub selected_year_gap_scalar_raw_u32: Option<u32>,
#[serde(default)]
pub selected_year_gap_scalar_raw_hex: Option<String>,
#[serde(default)]
pub selected_year_gap_scalar_value_f32_text: Option<String>,
#[serde(default)]
pub linked_site_removal_follow_on_gate_raw_u8: Option<u8>,
#[serde(default)]
pub linked_site_removal_follow_on_gate_raw_hex: Option<String>,
#[serde(default)]
pub auto_show_grade_during_track_lay_raw_u8: Option<u8>,
#[serde(default)]
pub auto_show_grade_during_track_lay_raw_hex: Option<String>,
#[serde(default)]
pub starting_building_density_level_raw_u8: Option<u8>,
#[serde(default)]
pub starting_building_density_level_raw_hex: Option<String>,
#[serde(default)]
pub building_density_growth_raw_u8: Option<u8>,
#[serde(default)]
pub building_density_growth_raw_hex: Option<String>,
#[serde(default)]
pub leftover_simulation_time_accumulator_raw_u32: Option<u32>,
#[serde(default)]
pub leftover_simulation_time_accumulator_raw_hex: Option<String>,
#[serde(default)]
pub leftover_simulation_time_accumulator_value_f32_text: Option<String>,
#[serde(default)]
pub selected_year_lane_snapshot_raw_u8: Option<u8>,
#[serde(default)]
pub selected_year_lane_snapshot_raw_hex: Option<String>,
#[serde(default)]
pub all_steam_locomotives_available_raw_u8: Option<u8>,
#[serde(default)]
pub all_steam_locomotives_available_raw_hex: Option<String>,
#[serde(default)]
pub all_diesel_locomotives_available_raw_u8: Option<u8>,
#[serde(default)]
pub all_diesel_locomotives_available_raw_hex: Option<String>,
#[serde(default)]
pub all_electric_locomotives_available_raw_u8: Option<u8>,
#[serde(default)]
pub all_electric_locomotives_available_raw_hex: Option<String>,
#[serde(default)]
pub cached_available_locomotive_rating_raw_u32: Option<u32>,
#[serde(default)]
pub cached_available_locomotive_rating_raw_hex: Option<String>,
#[serde(default)]
pub cached_available_locomotive_rating_value_f32_text: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCompanyRosterEntry {
pub company_id: u32,
pub active: bool,
#[serde(default)]
pub controller_kind: RuntimeCompanyControllerKind,
pub current_cash: i64,
pub debt: u64,
#[serde(default)]
pub credit_rating_score: Option<i64>,
#[serde(default)]
pub prime_rate: Option<i64>,
#[serde(default)]
pub available_track_laying_capacity: Option<u32>,
#[serde(default)]
pub track_piece_counts: RuntimeTrackPieceCounts,
#[serde(default)]
pub linked_chairman_profile_id: Option<u32>,
#[serde(default)]
pub book_value_per_share: i64,
#[serde(default)]
pub investor_confidence: i64,
#[serde(default)]
pub management_attitude: i64,
#[serde(default)]
pub takeover_cooldown_year: Option<u32>,
#[serde(default)]
pub merger_cooldown_year: Option<u32>,
#[serde(default)]
pub preferred_locomotive_engine_type_raw_u8: Option<u8>,
#[serde(default)]
pub market_state: Option<RuntimeCompanyMarketState>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCompanyRoster {
pub source_kind: String,
pub semantic_family: String,
pub observed_entry_count: usize,
#[serde(default)]
pub selected_company_id: Option<u32>,
pub entries: Vec<SmpLoadedCompanyRosterEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedChairmanProfileEntry {
pub profile_id: u32,
pub name: String,
pub active: bool,
#[serde(default)]
pub current_cash: i64,
#[serde(default)]
pub linked_company_id: Option<u32>,
#[serde(default)]
pub company_holdings: BTreeMap<u32, u32>,
#[serde(default)]
pub holdings_value_total: i64,
#[serde(default)]
pub net_worth_total: i64,
#[serde(default)]
pub purchasing_power_total: i64,
#[serde(default)]
pub personality_byte_0x291: Option<u8>,
#[serde(default)]
pub issue_opinion_terms_raw_i32: Vec<i32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedChairmanProfileTable {
pub source_kind: String,
pub semantic_family: String,
pub observed_entry_count: usize,
#[serde(default)]
pub selected_chairman_profile_id: Option<u32>,
pub entries: Vec<SmpLoadedChairmanProfileEntry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveScalarCandidate {
pub relative_offset: usize,
pub relative_offset_hex: String,
pub raw_u64: u64,
pub raw_u64_hex: String,
pub value_i64: i64,
pub value_f64: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveDwordCandidate {
pub label: String,
pub relative_offset: usize,
pub relative_offset_hex: String,
pub raw_u32: u32,
pub raw_u32_hex: String,
pub value_i32: i32,
pub value_f32: f32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveWorldSelectionRoleAnalysisEntry {
pub slot_index: usize,
pub selector_byte: u8,
pub selector_byte_hex: String,
pub role_gate_byte: u8,
pub role_gate_byte_hex: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpSaveWorldSelectionRoleAnalysis {
pub selected_company_id: u32,
pub selected_chairman_profile_id: u32,
pub campaign_override_flag: u8,
pub campaign_override_flag_hex: String,
pub chairman_slots: Vec<SmpSaveWorldSelectionRoleAnalysisEntry>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveCompanyRecordAnalysisEntry {
pub company_id: u32,
pub name: String,
pub active: bool,
#[serde(default)]
pub linked_chairman_profile_id: Option<u32>,
pub outstanding_shares: u32,
pub debt: u64,
pub bond_count: u8,
#[serde(default)]
pub live_bond_slots: Vec<crate::RuntimeCompanyBondSlot>,
#[serde(default)]
pub largest_live_bond_principal: Option<u32>,
#[serde(default)]
pub highest_coupon_live_bond_principal: Option<u32>,
#[serde(default)]
pub available_track_laying_capacity: Option<u32>,
pub company_value_scalar_f32: f32,
pub cached_share_support_scalar_f32: f32,
pub cached_share_price_f32: f32,
pub chairman_salary_baseline: u32,
pub chairman_salary_current: u32,
pub chairman_bonus_year: u32,
pub chairman_bonus_amount: i32,
pub founding_year: u32,
pub last_bankruptcy_year: u32,
pub last_dividend_year: u32,
pub preferred_locomotive_engine_type_raw_u8: u8,
pub preferred_locomotive_engine_type_raw_hex: String,
pub city_connection_latch: bool,
pub linked_transit_latch: bool,
pub merger_cooldown_year: u32,
pub takeover_cooldown_year: u32,
#[serde(default)]
pub scalar_dword_candidates: Vec<SmpSaveDwordCandidate>,
#[serde(default)]
pub post_capacity_dword_candidates: Vec<SmpSaveDwordCandidate>,
#[serde(default)]
pub stat_band_root_0cfb_candidates: Vec<SmpSaveDwordCandidate>,
#[serde(default)]
pub stat_band_root_0d7f_candidates: Vec<SmpSaveDwordCandidate>,
#[serde(default)]
pub stat_band_root_1c47_candidates: Vec<SmpSaveDwordCandidate>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveChairmanRecordAnalysisEntry {
pub profile_id: u32,
pub name: String,
pub active: bool,
pub current_cash: f64,
#[serde(default)]
pub linked_company_id: Option<u32>,
#[serde(default)]
pub holdings_by_company: BTreeMap<u32, u32>,
#[serde(default)]
pub derived_holdings_share_price_total: Option<i64>,
#[serde(default)]
pub derived_net_worth_share_price_total: Option<i64>,
#[serde(default)]
pub derived_cached_purchasing_power_total: Option<i64>,
pub personality_byte_0x291: u8,
pub personality_byte_0x291_hex: String,
#[serde(default)]
pub cached_scalar_candidates: Vec<SmpSaveScalarCandidate>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpSaveCompanyChairmanAnalysisReport {
pub profile_family: String,
#[serde(default)]
pub selected_company_id: Option<u32>,
#[serde(default)]
pub selected_chairman_profile_id: Option<u32>,
#[serde(default)]
pub world_selection_context: Option<SmpSaveWorldSelectionRoleAnalysis>,
#[serde(default)]
pub world_issue_37: Option<SmpSaveWorldIssue37Probe>,
#[serde(default)]
pub world_economic_tuning: Option<SmpSaveWorldEconomicTuningProbe>,
#[serde(default)]
pub world_finance_neighborhood: Option<SmpSaveWorldFinanceNeighborhoodProbe>,
#[serde(default)]
pub train_collection_header: Option<SmpSaveTaggedCollectionHeaderProbe>,
#[serde(default)]
pub train_collection_directory: Option<SmpSaveTrainCollectionDirectoryProbe>,
#[serde(default)]
pub region_collection_header: Option<SmpSaveTaggedCollectionHeaderProbe>,
#[serde(default)]
pub region_record_triplets: Option<SmpSaveRegionRecordTripletProbe>,
#[serde(default)]
pub region_queued_notice_records: Option<SmpSaveRegionQueuedNoticeRecordProbe>,
#[serde(default)]
pub region_fixed_row_run_candidates: Option<SmpSaveRegionFixedRowRunCandidateProbe>,
#[serde(default)]
pub placed_structure_collection_header: Option<SmpSaveTaggedCollectionHeaderProbe>,
#[serde(default)]
pub placed_structure_record_triplets: Option<SmpSavePlacedStructureRecordTripletProbe>,
#[serde(default)]
pub placed_structure_dynamic_side_buffer: Option<SmpSavePlacedStructureDynamicSideBufferProbe>,
#[serde(default)]
pub placed_structure_dynamic_side_buffer_alignment:
Option<SmpSavePlacedStructureDynamicSideBufferAlignmentProbe>,
#[serde(default)]
pub unclassified_tagged_collection_headers: Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>,
#[serde(default)]
pub company_entries: Vec<SmpSaveCompanyRecordAnalysisEntry>,
#[serde(default)]
pub chairman_entries: Vec<SmpSaveChairmanRecordAnalysisEntry>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpServiceTraceBranchStatus {
pub branch_name: String,
pub status: String,
#[serde(default)]
pub grounded_inputs: Vec<String>,
#[serde(default)]
pub blocking_inputs: Vec<String>,
#[serde(default)]
pub candidate_consumers: Vec<String>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPeriodicCompanyServiceTraceEntry {
pub company_id: u32,
pub name: String,
pub active: bool,
#[serde(default)]
pub linked_chairman_profile_id: Option<u32>,
pub preferred_locomotive_engine_type_raw_u8: u8,
pub city_connection_latch: bool,
pub linked_transit_latch: bool,
#[serde(default)]
pub branches: Vec<SmpServiceTraceBranchStatus>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPeriodicCompanyServiceTraceReport {
pub profile_family: String,
#[serde(default)]
pub selected_company_id: Option<u32>,
#[serde(default)]
pub world_issue_37_present: bool,
#[serde(default)]
pub world_finance_neighborhood_present: bool,
#[serde(default)]
pub region_record_body_present: bool,
#[serde(default)]
pub placed_structure_record_body_present: bool,
#[serde(default)]
pub infrastructure_asset_side_buffer_present: bool,
pub peer_site_selector_candidate_owner_strip: String,
pub peer_site_selector_candidate_persisted_tag_hex: String,
pub peer_site_selector_candidate_selector_lane: String,
pub peer_site_selector_candidate_class_identity_status: String,
#[serde(default)]
pub peer_site_selector_candidate_helper_linkage: Vec<String>,
#[serde(default)]
pub peer_site_restore_input_fields: Vec<String>,
#[serde(default)]
pub peer_site_runtime_input_fields: Vec<String>,
pub peer_site_runtime_reconstruction_status: String,
#[serde(default)]
pub peer_site_runtime_reconstruction_steps: Vec<String>,
#[serde(default)]
pub near_city_acquisition_region_input_fields: Vec<String>,
#[serde(default)]
pub near_city_acquisition_peer_input_fields: Vec<String>,
#[serde(default)]
pub near_city_acquisition_company_input_fields: Vec<String>,
pub near_city_acquisition_shellless_readiness_status: String,
#[serde(default)]
pub near_city_acquisition_runtime_backed_input_families: Vec<String>,
#[serde(default)]
pub near_city_acquisition_remaining_owner_gaps: Vec<String>,
#[serde(default)]
pub near_city_acquisition_region_lane_statuses: Vec<String>,
#[serde(default)]
pub atlas_candidate_consumers: Vec<String>,
#[serde(default)]
pub known_bridge_helpers: Vec<String>,
#[serde(default)]
pub next_owner_questions: Vec<String>,
#[serde(default)]
pub companies: Vec<SmpPeriodicCompanyServiceTraceEntry>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRegionServiceTraceEntry {
pub name: String,
#[serde(default)]
pub profile_collection_count: Option<u32>,
pub policy_leading_f32_0_text: String,
pub policy_leading_f32_1_text: String,
pub policy_leading_f32_2_text: String,
#[serde(default)]
pub policy_reserved_dword_hex_words: Vec<String>,
pub policy_trailing_word_hex: String,
#[serde(default)]
pub branches: Vec<SmpServiceTraceBranchStatus>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpRegionServiceTraceReport {
pub profile_family: String,
#[serde(default)]
pub region_collection_header_present: bool,
#[serde(default)]
pub region_record_triplet_count: usize,
#[serde(default)]
pub queued_notice_record_count: usize,
#[serde(default)]
pub atlas_candidate_consumers: Vec<String>,
#[serde(default)]
pub known_owner_bridge_fields: Vec<String>,
#[serde(default)]
pub known_bridge_helpers: Vec<String>,
#[serde(default)]
pub next_owner_questions: Vec<String>,
#[serde(default)]
pub candidate_consumer_hypotheses: Vec<SmpServiceConsumerHypothesis>,
#[serde(default)]
pub entries: Vec<SmpRegionServiceTraceEntry>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpInfrastructureAssetTraceReport {
pub profile_family: String,
#[serde(default)]
pub placed_structure_collection_header_present: bool,
#[serde(default)]
pub placed_structure_record_triplet_count: usize,
#[serde(default)]
pub side_buffer_present: bool,
#[serde(default)]
pub side_buffer_decoded_embedded_name_row_count: usize,
#[serde(default)]
pub side_buffer_unique_name_pair_count: usize,
#[serde(default)]
pub bridge_like_name_pair_count: usize,
#[serde(default)]
pub tunnel_like_name_pair_count: usize,
#[serde(default)]
pub track_cap_like_name_pair_count: usize,
#[serde(default)]
pub triplet_alignment_overlap_count: usize,
#[serde(default)]
pub atlas_candidate_consumers: Vec<String>,
#[serde(default)]
pub known_owner_bridge_fields: Vec<String>,
#[serde(default)]
pub known_bridge_helpers: Vec<String>,
#[serde(default)]
pub next_owner_questions: Vec<String>,
#[serde(default)]
pub candidate_consumer_hypotheses: Vec<SmpServiceConsumerHypothesis>,
#[serde(default)]
pub branches: Vec<SmpServiceTraceBranchStatus>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpServiceConsumerHypothesis {
pub label: String,
pub status: String,
#[serde(default)]
pub candidate_consumers: Vec<String>,
#[serde(default)]
pub evidence: Vec<String>,
#[serde(default)]
pub blockers: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedSpecialConditionsTable {
pub source_kind: String,
pub table_offset: usize,
pub table_len: usize,
pub enabled_visible_count: usize,
pub enabled_visible_labels: Vec<String>,
pub entries: Vec<SmpSpecialConditionEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedEventRuntimeCollectionSummary {
pub source_kind: String,
pub mechanism_family: String,
pub mechanism_confidence: String,
#[serde(default)]
pub container_profile_family: Option<String>,
pub metadata_tag_offset: usize,
pub records_tag_offset: usize,
pub close_tag_offset: usize,
pub packed_state_version: u32,
pub packed_state_version_hex: String,
pub live_id_bound: u32,
pub live_record_count: usize,
pub live_entry_ids: Vec<u32>,
#[serde(default)]
pub decoded_record_count: usize,
#[serde(default)]
pub imported_runtime_record_count: usize,
#[serde(default)]
pub records: Vec<SmpLoadedPackedEventRecordSummary>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventRecordSummary {
pub record_index: usize,
pub live_entry_id: u32,
#[serde(default)]
pub payload_offset: Option<usize>,
#[serde(default)]
pub payload_len: Option<usize>,
pub decode_status: String,
#[serde(default)]
pub payload_family: String,
#[serde(default)]
pub trigger_kind: Option<u8>,
#[serde(default)]
pub active: Option<bool>,
#[serde(default)]
pub marks_collection_dirty: Option<bool>,
#[serde(default)]
pub one_shot: Option<bool>,
#[serde(default)]
pub compact_control: Option<SmpLoadedPackedEventCompactControlSummary>,
#[serde(default)]
pub text_bands: Vec<SmpLoadedPackedEventTextBandSummary>,
#[serde(default)]
pub standalone_condition_row_count: usize,
#[serde(default)]
pub standalone_condition_rows: Vec<SmpLoadedPackedEventConditionRowSummary>,
#[serde(default)]
pub negative_sentinel_scope: Option<SmpLoadedPackedEventNegativeSentinelScopeSummary>,
#[serde(default)]
pub grouped_effect_row_counts: Vec<usize>,
#[serde(default)]
pub grouped_effect_rows: Vec<SmpLoadedPackedEventGroupedEffectRowSummary>,
#[serde(default)]
pub decoded_conditions: Vec<RuntimeCondition>,
#[serde(default)]
pub decoded_actions: Vec<RuntimeEffect>,
#[serde(default)]
pub executable_import_ready: bool,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventNegativeSentinelScopeSummary {
pub company_test_scope: RuntimeCompanyConditionTestScope,
pub player_test_scope: RuntimePlayerConditionTestScope,
pub territory_scope_selector_is_0x63: bool,
#[serde(default)]
pub source_row_indexes: Vec<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventCompactControlSummary {
pub mode_byte_0x7ef: u8,
pub primary_selector_0x7f0: u32,
pub grouped_mode_0x7f4: u8,
pub one_shot_header_0x7f5: u32,
pub modifier_flag_0x7f9: u8,
pub modifier_flag_0x7fa: u8,
pub grouped_target_scope_ordinals_0x7fb: Vec<u8>,
pub grouped_scope_checkboxes_0x7ff: Vec<u8>,
pub summary_toggle_0x800: u8,
pub grouped_territory_selectors_0x80f: Vec<i32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventTextBandSummary {
pub label: String,
pub packed_len: usize,
pub present: bool,
pub preview: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventConditionRowSummary {
pub row_index: usize,
pub raw_condition_id: i32,
pub subtype: u8,
#[serde(default)]
pub flag_bytes: Vec<u8>,
#[serde(default)]
pub candidate_name: Option<String>,
#[serde(default)]
pub comparator: Option<String>,
#[serde(default)]
pub metric: Option<String>,
#[serde(default)]
pub semantic_family: Option<String>,
#[serde(default)]
pub semantic_preview: Option<String>,
#[serde(default)]
pub recovered_cargo_slot: Option<u32>,
#[serde(default)]
pub recovered_cargo_class: Option<String>,
#[serde(default)]
pub requires_candidate_name_binding: bool,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedPackedEventGroupedEffectRowSummary {
pub group_index: usize,
pub row_index: usize,
pub descriptor_id: u32,
#[serde(default)]
pub descriptor_label: Option<String>,
#[serde(default)]
pub target_mask_bits: Option<u8>,
#[serde(default)]
pub parameter_family: Option<String>,
#[serde(default)]
pub grouped_target_subject: Option<String>,
#[serde(default)]
pub grouped_target_scope: Option<String>,
pub opcode: u8,
pub raw_scalar_value: i32,
pub value_byte_0x09: u8,
pub value_dword_0x0d: u32,
pub value_byte_0x11: u8,
pub value_byte_0x12: u8,
pub value_word_0x14: u16,
pub value_word_0x16: u16,
pub row_shape: String,
#[serde(default)]
pub semantic_family: Option<String>,
#[serde(default)]
pub semantic_preview: Option<String>,
#[serde(default)]
pub recovered_cargo_slot: Option<u32>,
#[serde(default)]
pub recovered_cargo_class: Option<String>,
#[serde(default)]
pub recovered_cargo_label: Option<String>,
#[serde(default)]
pub recovered_locomotive_id: Option<u32>,
#[serde(default)]
pub locomotive_name: Option<String>,
#[serde(default)]
pub notes: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RealGroupedTargetSubject {
Company,
Player,
Chairman,
Territory,
WholeGame,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedSaveSlice {
pub file_extension_hint: Option<String>,
pub container_profile_family: Option<String>,
pub mechanism_family: String,
pub mechanism_confidence: String,
pub trailer_family: Option<String>,
pub bridge_family: Option<String>,
pub profile: Option<SmpLoadedProfile>,
pub candidate_availability_table: Option<SmpLoadedCandidateAvailabilityTable>,
pub named_locomotive_availability_table: Option<SmpLoadedNamedLocomotiveAvailabilityTable>,
#[serde(default)]
pub locomotive_catalog: Option<SmpLoadedLocomotiveCatalog>,
#[serde(default)]
pub cargo_catalog: Option<SmpLoadedCargoCatalog>,
#[serde(default)]
pub world_issue_37_state: Option<SmpLoadedWorldIssue37State>,
#[serde(default)]
pub world_economic_tuning_state: Option<SmpLoadedWorldEconomicTuningState>,
#[serde(default)]
pub world_finance_neighborhood_state: Option<SmpLoadedWorldFinanceNeighborhoodState>,
#[serde(default)]
pub world_locomotive_policy_state: Option<SmpLoadedWorldLocomotivePolicyState>,
#[serde(default)]
pub company_roster: Option<SmpLoadedCompanyRoster>,
#[serde(default)]
pub chairman_profile_table: Option<SmpLoadedChairmanProfileTable>,
pub special_conditions_table: Option<SmpLoadedSpecialConditionsTable>,
pub event_runtime_collection: Option<SmpLoadedEventRuntimeCollectionSummary>,
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpPackedProfileWordLane {
pub relative_offset: usize,
pub relative_offset_hex: String,
pub value: u32,
pub value_hex: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SmpInspectionReport {
pub inspection_mode: String,
pub file_extension_hint: Option<String>,
pub file_size: usize,
pub sha256: String,
pub preamble: SmpPreamble,
pub shared_header: Option<SmpSharedHeader>,
pub header_variant_probe: Option<SmpHeaderVariantProbe>,
pub first_ascii_run: Option<SmpAsciiPreview>,
pub early_content_probe: Option<SmpEarlyContentProbe>,
pub secondary_variant_probe: Option<SmpSecondaryVariantProbe>,
pub container_profile: Option<SmpContainerProfile>,
pub save_bootstrap_block: Option<SmpSaveBootstrapBlock>,
pub save_anchor_run_block: Option<SmpSaveAnchorRunBlock>,
pub runtime_anchor_cycle_block: Option<SmpRuntimeAnchorCycleBlock>,
pub runtime_trailer_block: Option<SmpRuntimeTrailerBlock>,
pub runtime_post_span_probe: Option<SmpRuntimePostSpanProbe>,
pub rt3_105_post_span_bridge_probe: Option<SmpRt3105PostSpanBridgeProbe>,
pub rt3_105_save_bridge_payload_probe: Option<SmpRt3105SaveBridgePayloadProbe>,
pub save_world_selection_context_probe: Option<SmpSaveWorldSelectionContextProbe>,
pub save_world_issue_37_probe: Option<SmpSaveWorldIssue37Probe>,
pub save_world_economic_tuning_probe: Option<SmpSaveWorldEconomicTuningProbe>,
pub save_world_finance_neighborhood_probe: Option<SmpSaveWorldFinanceNeighborhoodProbe>,
pub save_company_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
pub save_chairman_profile_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
pub save_train_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
pub save_train_collection_directory_probe: Option<SmpSaveTrainCollectionDirectoryProbe>,
pub save_region_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
pub save_region_record_triplet_probe: Option<SmpSaveRegionRecordTripletProbe>,
#[serde(default)]
pub save_region_queued_notice_record_probe: Option<SmpSaveRegionQueuedNoticeRecordProbe>,
#[serde(default)]
pub save_region_fixed_row_run_candidate_probe: Option<SmpSaveRegionFixedRowRunCandidateProbe>,
pub save_placed_structure_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
pub save_placed_structure_record_triplet_probe:
Option<SmpSavePlacedStructureRecordTripletProbe>,
#[serde(default)]
pub save_placed_structure_dynamic_side_buffer_probe:
Option<SmpSavePlacedStructureDynamicSideBufferProbe>,
#[serde(default)]
pub save_unclassified_tagged_collection_header_probes:
Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>,
#[serde(default)]
pub save_company_roster_probe: Option<SmpLoadedCompanyRoster>,
#[serde(default)]
pub save_chairman_profile_table_probe: Option<SmpLoadedChairmanProfileTable>,
pub rt3_105_save_name_table_probe: Option<SmpRt3105SaveNameTableProbe>,
pub rt3_105_save_named_locomotive_availability_probe:
Option<SmpRt3105SaveNamedLocomotiveAvailabilityProbe>,
pub special_conditions_probe: Option<SmpSpecialConditionsProbe>,
pub smp_aligned_runtime_rule_band_probe: Option<SmpAlignedRuntimeRuleBandProbe>,
pub post_special_conditions_scalar_probe: Option<SmpPostSpecialConditionsScalarProbe>,
pub post_text_field_neighborhood_probe: Option<SmpPostTextFieldNeighborhoodProbe>,
pub locomotive_policy_neighborhood_probe: Option<SmpLocomotivePolicyNeighborhoodProbe>,
pub pre_recipe_scalar_plateau_probe: Option<SmpPreRecipeScalarPlateauProbe>,
pub recipe_book_summary_probe: Option<SmpRecipeBookSummaryProbe>,
pub classic_rehydrate_profile_probe: Option<SmpClassicRehydrateProfileProbe>,
pub rt3_105_packed_profile_probe: Option<SmpRt3105PackedProfileProbe>,
pub save_load_summary: Option<SmpSaveLoadSummary>,
pub event_runtime_collection_summary: Option<SmpLoadedEventRuntimeCollectionSummary>,
pub contains_grounded_runtime_tags: bool,
pub known_tag_hits: Vec<SmpKnownTagHit>,
pub notes: Vec<String>,
pub warnings: Vec<String>,
}
pub fn inspect_smp_file(path: &Path) -> Result<SmpInspectionReport, Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
Ok(inspect_bundle_bytes(
&bytes,
path.extension()
.and_then(|extension| extension.to_str())
.map(|extension| extension.to_ascii_lowercase()),
))
}
pub fn inspect_unclassified_save_collection_headers_file(
path: &Path,
) -> Result<Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>, Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
let file_extension_hint = path
.extension()
.and_then(|extension| extension.to_str())
.map(|extension| extension.to_ascii_lowercase());
let shared_header = parse_shared_header(&bytes);
let header_variant_probe = shared_header.as_ref().map(classify_header_variant_probe);
let first_ascii_run = find_first_ascii_run(&bytes);
let early_content_probe = first_ascii_run
.as_ref()
.and_then(|ascii_run| probe_early_content_layout(&bytes, ascii_run));
let secondary_variant_probe = early_content_probe
.as_ref()
.and_then(classify_secondary_variant_probe);
let container_profile = classify_container_profile(
file_extension_hint.as_deref(),
header_variant_probe.as_ref(),
secondary_variant_probe.as_ref(),
);
let save_company_collection_header_probe = parse_save_company_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_chairman_profile_collection_header_probe =
parse_save_chairman_profile_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_train_collection_header_probe = parse_save_train_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_region_collection_header_probe = parse_save_region_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_placed_structure_collection_header_probe =
parse_save_placed_structure_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let known_header_probes = [
save_company_collection_header_probe.as_ref(),
save_chairman_profile_collection_header_probe.as_ref(),
save_train_collection_header_probe.as_ref(),
save_region_collection_header_probe.as_ref(),
save_placed_structure_collection_header_probe.as_ref(),
];
let probes = scan_save_unclassified_tagged_collection_header_probes(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
Ok(
filter_unclassified_tagged_collection_header_probes_outside_known_spans(
probes,
&known_header_probes,
),
)
}
pub fn inspect_save_placed_structure_dynamic_side_buffer_file(
path: &Path,
) -> Result<Option<SmpSavePlacedStructureDynamicSideBufferProbe>, Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
let file_extension_hint = path
.extension()
.and_then(|extension| extension.to_str())
.map(|extension| extension.to_ascii_lowercase());
let shared_header = parse_shared_header(&bytes);
let header_variant_probe = shared_header.as_ref().map(classify_header_variant_probe);
let first_ascii_run = find_first_ascii_run(&bytes);
let early_content_probe = first_ascii_run
.as_ref()
.and_then(|ascii_run| probe_early_content_layout(&bytes, ascii_run));
let secondary_variant_probe = early_content_probe
.as_ref()
.and_then(classify_secondary_variant_probe);
let container_profile = classify_container_profile(
file_extension_hint.as_deref(),
header_variant_probe.as_ref(),
secondary_variant_probe.as_ref(),
);
Ok(parse_save_placed_structure_dynamic_side_buffer_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
))
}
pub fn inspect_save_region_queued_notice_records_file(
path: &Path,
) -> Result<Option<SmpSaveRegionQueuedNoticeRecordProbe>, Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
let file_extension_hint = path
.extension()
.and_then(|extension| extension.to_str())
.map(|extension| extension.to_ascii_lowercase());
let shared_header = parse_shared_header(&bytes);
let header_variant_probe = shared_header.as_ref().map(classify_header_variant_probe);
let first_ascii_run = find_first_ascii_run(&bytes);
let early_content_probe = first_ascii_run
.as_ref()
.and_then(|ascii_run| probe_early_content_layout(&bytes, ascii_run));
let secondary_variant_probe = early_content_probe
.as_ref()
.and_then(classify_secondary_variant_probe);
let container_profile = classify_container_profile(
file_extension_hint.as_deref(),
header_variant_probe.as_ref(),
secondary_variant_probe.as_ref(),
);
let save_region_collection_header_probe = parse_save_region_collection_header_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
Ok(parse_save_region_queued_notice_record_probe(
&bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
save_region_collection_header_probe.as_ref(),
))
}
fn build_service_trace_branch_status(
branch_name: &str,
status: &str,
grounded_inputs: &[&str],
blocking_inputs: &[&str],
candidate_consumers: &[&str],
notes: &[&str],
) -> SmpServiceTraceBranchStatus {
SmpServiceTraceBranchStatus {
branch_name: branch_name.to_string(),
status: status.to_string(),
grounded_inputs: grounded_inputs
.iter()
.map(|value| value.to_string())
.collect(),
blocking_inputs: blocking_inputs
.iter()
.map(|value| value.to_string())
.collect(),
candidate_consumers: candidate_consumers
.iter()
.map(|value| value.to_string())
.collect(),
notes: notes.iter().map(|value| value.to_string()).collect(),
}
}
pub fn inspect_save_periodic_company_service_trace_file(
path: &Path,
) -> Result<SmpPeriodicCompanyServiceTraceReport, Box<dyn std::error::Error>> {
let inspection = inspect_smp_file(path)?;
let analysis = inspect_save_company_and_chairman_analysis_file(path)?;
let mut trace = build_periodic_company_service_trace_report(&analysis);
let _ = inspection;
if trace.region_record_body_present || trace.placed_structure_record_body_present {
trace.notes.push(
"The current blockers are no longer collection identity; they are missing higher-layer consumer semantics for the region and infrastructure/placed-structure owner seams.".to_string(),
);
}
Ok(trace)
}
fn build_periodic_company_service_trace_report(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> SmpPeriodicCompanyServiceTraceReport {
let profile_family = analysis.profile_family.clone();
let selected_company_id = analysis.selected_company_id;
let region_record_body_present = analysis.region_record_triplets.is_some();
let placed_structure_record_body_present = analysis.placed_structure_record_triplets.is_some();
let infrastructure_asset_side_buffer_present =
analysis.placed_structure_dynamic_side_buffer.is_some();
let world_issue_37_present = analysis.world_issue_37.is_some();
let world_finance_neighborhood_present = analysis.world_finance_neighborhood.is_some();
let peer_site_selector_candidate_owner_strip =
"0x0045c150 -> 0x0045c310 -> 0x0045c36e -> 0x00456100 -> 0x00455b70".to_string();
let peer_site_selector_candidate_persisted_tag_hex = "0x5dc1".to_string();
let peer_site_selector_candidate_selector_lane = "[owner+0x23e]".to_string();
let peer_site_selector_candidate_class_identity_status =
"grounded_direct_local_helper_strip".to_string();
let peer_site_selector_candidate_helper_linkage = vec![
"0x0040ceab -> 0x0045c150".to_string(),
"0x0040d1a1 -> 0x0045c310".to_string(),
"0x0040cd70 seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268".to_string(),
"0x0040d1e1 -> 0x0045c3c0 consumes the same owner family's [site+0x246] child lane"
.to_string(),
];
let peer_site_restore_input_fields = vec![
"[site+0x3cc] saved placed-structure id feeding 0x62b2fc".to_string(),
"[site+0x3d0] saved companion-region id from [placed+0x173] feeding 0x62b268".to_string(),
"0x5dc1 payload lane [owner+0x23e] feeding 0x0045c36e selector arg 1".to_string(),
"0x5dc1 payload lane [owner+0x242] companion lane paired with [owner+0x23e]".to_string(),
];
let peer_site_runtime_input_fields = vec![
"[site+0x04] live backing-record selector consumed by 0x0047efe0 / 0x0047fd50".to_string(),
"[site+0x2a8] linked peer-site id consumed by 0x0040d1f0".to_string(),
"[peer+0x08] route-entry anchor id consumed by 0x0047dda0".to_string(),
];
let peer_site_runtime_reconstruction_status =
"restore_subset_and_bring_up_reconstruct_runtime_subset".to_string();
let peer_site_runtime_reconstruction_steps = vec![
"[site+0x04] restored from 0x0045c150 -> 0x0045c310 -> 0x0045c36e -> 0x00456100 -> 0x00455b70 -> 0x0052edf0"
.to_string(),
"[site+0x2a8] rewritten by 0x0040f6d0 after 0x00481390 returns the linked peer id"
.to_string(),
"[peer+0x08] refreshed during 0x00444690 -> 0x004133b0 -> 0x0040ee10 -> 0x0040edf6 -> 0x00480710"
.to_string(),
];
let near_city_acquisition_region_input_fields = vec![
"[region+0x276] pending amount gate".to_string(),
"region vtable +0x80 byte-0x32 class filter consumed through 0x0040d360".to_string(),
"[region+0x3d5] age/year delta lane".to_string(),
"[region+0x310/+0x338/+0x360] cached tri-lane sampled through 0x0040cac0".to_string(),
"[region+0x2a4] winning linked company id output lane".to_string(),
];
let near_city_acquisition_peer_input_fields = vec![
"center-cell token gate 0x0041f6e0 -> 0x0042b2d0 over the current region".to_string(),
"[site+0x04] live backing-record selector consumed by 0x0047efe0 / 0x0047fd50".to_string(),
"[site+0x2a8] linked peer-site id consumed by 0x0040d1f0".to_string(),
"[peer+0x08] route-entry anchor id consumed by 0x0047dda0".to_string(),
"linked-region status branch 0x0047de00 -> 0x0040c990".to_string(),
];
let near_city_acquisition_company_input_fields = vec![
"company stat-family reader 0x2329/0x0d through 0x0042a5d0".to_string(),
"current chairman profile byte [profile+0x291] through 0x00426ef0".to_string(),
"company byte [company+0x5b] and indexed lane [company+0x67 + 12*0x0042a0e0()]".to_string(),
"company-root argument [company+0x00] passed into 0x0040d540 and 0x00455f60".to_string(),
];
let near_city_acquisition_shellless_readiness_status =
"peer_and_company_inputs_grounded_region_restore_gap_remaining".to_string();
let near_city_acquisition_runtime_backed_input_families = vec![
"peer-site restore subset [site+0x3cc/+0x3d0] plus tagged 0x5dc1 [owner+0x23e/+0x242]"
.to_string(),
"peer-site bring-up replay path reconstructing [site+0x04], [site+0x2a8], and [peer+0x08]"
.to_string(),
"company stat-family lane 0x2329/0x0d already rehosted in runtime company state".to_string(),
"chairman personality byte [profile+0x291] already reconstructed from raw save chairman rows"
.to_string(),
"company-root pointer and linked chairman/company save-native roster identity already imported"
.to_string(),
];
let near_city_acquisition_remaining_owner_gaps = vec![
"save restore owner for [region+0x276] pending amount on ordinary saves, even though runtime producer 0x00422100 is grounded".to_string(),
"save payload or restore owner for [region+0x2a4] winning linked-company lane; current binary scan finds no region-class runtime writer".to_string(),
"save payload or restore owner for [region+0x310/+0x338/+0x360] cached tri-lane sampled by 0x0040cac0; current binary scan finds no direct region-class runtime writer".to_string(),
"save-native projection of the region type byte consumed by 0x0040d360 as [owner_vtable+0x80+0x32] == 4".to_string(),
];
let near_city_acquisition_region_lane_statuses = vec![
"[region+0x276] pending amount lane: runtime producer grounded at 0x00422100, ordinary-save restore owner still missing".to_string(),
"[region+0x2a4] winning linked-company lane: consumed by 0x004014b0 and 0x0044554e0 path, no region-class runtime writer found in current binary scan".to_string(),
"[region+0x310/+0x338/+0x360] cached tri-lane: exact raw delta reader grounded at 0x0040cac0, and the current binary write scan finds no direct region-class runtime writer, so the lane now looks payload/restore-owned".to_string(),
"region type filter: 0x0040d360 is the exact test [owner_vtable+0x80+0x32] == 4, but the save-native projection of that byte is still missing".to_string(),
];
let atlas_candidate_consumers = vec![
"0x004019e0 periodic company outer service owner".to_string(),
"0x00406050 city-connection bonus/news owner".to_string(),
"0x00409950 linked-transit train-roster balancer".to_string(),
"0x004014b0 near-city industry acquisition and news owner".to_string(),
"0x00401c50 annual finance-policy owner".to_string(),
"0x00420030 / 0x00420280 peer-site boolean/selector pair over 0x006cec20".to_string(),
"0x004093d0 / 0x00407bd0 linked-transit refresh tails".to_string(),
];
let known_bridge_helpers = vec![
"0x004078a0 preferred-locomotive chooser feeding company byte 0x0d17".to_string(),
"0x0041d550 locomotive-era and engine-type approval gate over scenario opinion lanes"
.to_string(),
"0x004010f0 near-city acquisition region scorer over class-0 region entries".to_string(),
"0x00405920 same-company industry proximity aggregator over linked site peers".to_string(),
"0x0041f6e0 center-cell token gate feeding 0x0042b2d0 over the current region".to_string(),
"0x0042b2d0 packed-u16 contains-key predicate over the region token list".to_string(),
"0x0047de00 linked-region resolver feeding the candidate status branch 0x0040c990"
.to_string(),
"0x004801a0 linked-transit route-anchor reachability gate for one candidate site"
.to_string(),
"0x00425b90 pending-bonus/company-state gate over the [region+0x276] companion object"
.to_string(),
"0x0040cac0 region cached tri-lane delta sampler over [region+0x310/+0x338/+0x360]"
.to_string(),
"0x0040d360 region type/class filter over the region vtable +0x80 byte-0x32 lane"
.to_string(),
"0x0040d540 weighted region-to-company proximity scorer with pending-bonus context"
.to_string(),
"0x0040f6d0 subtype-1 placed-structure constructor writing linked peer id via 0x00481390"
.to_string(),
"0x00481390 / 0x00480210 subtype-1 linked-site allocation and constructor".to_string(),
"0x00444690 late world bring-up caller of 0x004133b0 placed-structure local-runtime replay"
.to_string(),
"0x004133b0 placed-structure local-runtime replay owner draining queued site ids through 0x0040e450 and sweeping live sites through 0x0040ee10".to_string(),
"0x0040e450 queued site-id cloned local-runtime replay helper".to_string(),
"0x0040ee10 live-site position/scalar refresh helper reaching 0x0040edf6 -> 0x00480710 and 0x0040e360".to_string(),
"0x00480710 linked-site runtime side-buffer and route-entry-anchor refresh owner"
.to_string(),
"0x0040df27 / 0x0040e00a / 0x0040edf6 concrete linked-site side-refresh callers of 0x00480710"
.to_string(),
"0x004160aa non-bring-up runtime caller of 0x0040ee10".to_string(),
"0x0048abc0 / 0x00493cf0 route-entry-anchor rebind and synthesis strip".to_string(),
"0x0047dda0 linked-peer route-entry-anchor validator".to_string(),
"0x00420030 / 0x00420280 peer-site boolean/selector pair over the placed-structure collection".to_string(),
"0x0047efe0 placed-structure linked-company resolver".to_string(),
"0x0052edf0 generic base constructor seeding [this+0x04] from caller arg 1".to_string(),
"0x00455b70 placed-structure specialization constructor feeding 0x0052edf0 arg 3 as the primary selector and arg 1 as fallback"
.to_string(),
"0x00455c62 concrete placed-structure specialization caller of 0x0052edf0".to_string(),
"0x00456100 local wrapper duplicating its first incoming arg across the 0x00455b70 selector/fallback bundle"
.to_string(),
"0x00456072 fixed 0x55f2 callback forwarding three local dwords plus unit scalars into 0x00455b70"
.to_string(),
"0x0045c36e / 0x0045da65 / 0x0045e0fc dense 0x00456100 caller family over stack-backed buffers and default scalar lanes"
.to_string(),
"0x0045c36e feeds 0x00456100 selector arg 1 from [owner+0x23e], 0x0045da65 feeds zero, and 0x0045e0fc feeds [ebp+0x08]"
.to_string(),
"0x0045c150 save-backed loader for [owner+0x23e/+0x242] via tagged payload 0x5dc1 ahead of 0x0045c310"
.to_string(),
"0x0040ceab / 0x0040d1a1 local linked-site helper strip calling 0x0045c150 / 0x0045c310 directly"
.to_string(),
"0x00485819 typed placed-structure caller of 0x0052edf0 via 0x530640-style argument bundle"
.to_string(),
"0x00490a79 chooser-side caller of 0x00455b70 with literal selector 0x005cfd74 and fallback seed 0x005c87a8"
.to_string(),
"0x00406050 city-connection bonus/news sibling owner".to_string(),
"0x00409950 linked-transit roster sibling owner".to_string(),
];
let next_owner_questions = vec![
"Which persisted region and company linkage fields are still missing for a shellless 0x004014b0 implementation once the peer-site restore subset is accepted as sufficient to reconstruct the live runtime subset?".to_string(),
"How much of the linked-peer refresh path is strictly post-load versus recurring runtime maintenance now that 0x004133b0 reaches 0x0040ee10 -> 0x0040edf6 -> 0x00480710 during bring-up and 0x004160aa also re-enters 0x0040ee10 later?".to_string(),
"Which later save payload or restore owner rehydrates the remaining region-side 0x004014b0 inputs [region+0x2a4] and [region+0x310/+0x338/+0x360] once peer/company inputs are accepted as grounded and [region+0x276] is treated as a producer-known ordinary-save restore gap?".to_string(),
"Which infrastructure consumer above the grounded 0x38a5 seam actually drives the linked-transit branch that 0x00409950 follows?".to_string(),
];
let companies = analysis
.company_entries
.iter()
.map(|entry| {
let mut branches = Vec::new();
branches.push(build_service_trace_branch_status(
"route_preference_override",
if entry.preferred_locomotive_engine_type_raw_u8 == 2 {
"grounded_electric_override_candidate"
} else {
"grounded_non_electric_or_inactive_override_candidate"
},
&[
"company periodic side-latch trio",
"world route-preference byte",
"preferred locomotive engine-type lane",
],
&[],
&[
"0x004019e0 periodic company outer owner",
"0x004078a0 preferred-locomotive chooser",
"0x0041d550 locomotive-era and engine-type approval gate",
],
&[
"This probe keeps the outer owner at the save-owned input level; the concrete runtime reader/apply/restore seam is already grounded separately.",
],
));
branches.push(build_service_trace_branch_status(
"annual_finance_policy",
"runnable_from_grounded_owner_state",
&[
"company market/cache owner state",
"periodic side-latches",
"world issue/timing owner state",
"derived annual-finance readers",
],
&[],
&[
"0x004019e0 periodic company outer owner",
"0x00401c50 annual finance-policy owner",
],
&[
"The shellless annual-finance helper is already rehosted on top of runtime-owned state.",
],
));
branches.push(build_service_trace_branch_status(
"city_connection_announcement",
"blocked_missing_region_and_infrastructure_asset_owner_seams",
&[
"company periodic side-latches",
"route-preference override seam",
"annual-finance sequencing owner",
],
&[
"region pending/completion/one-shot/severity lanes",
"stable region id or class discriminator",
"placed-structure or infrastructure-asset consumer mapping",
],
&[
"0x004019e0 periodic company outer owner",
"0x00406050 city-connection bonus/news owner",
"0x00420030 / 0x00420280 city-connection peer probes",
"0x0047efe0 placed-structure linked-company resolver",
],
&[
"Current atlas evidence places this branch above both the region pending-bonus lane and infrastructure/placed-structure consumers.",
],
));
branches.push(build_service_trace_branch_status(
"linked_transit_roster_maintenance",
"blocked_missing_infrastructure_asset_consumer_mapping",
&[
"company linked-transit latch",
"route-preference override seam",
],
&[
"placed-structure record-body semantics",
"0x38a5 infrastructure-asset consumer mapping",
],
&[
"0x004019e0 periodic company outer owner",
"0x00409950 linked-transit train-roster balancer",
],
&[
"The save side now grounds the owner seams, but not yet the higher-layer consumer that turns them into roster or route actions.",
],
));
branches.push(build_service_trace_branch_status(
"industry_acquisition_side_branch",
"blocked_missing_near-city_owner_mapping",
&[
"periodic service outer owner",
"annual-finance ordering",
],
&[
"near-city industry candidate owner seam",
"city or region peer linkage",
],
&[
"0x004019e0 periodic company outer owner",
"0x004014b0 near-city industry acquisition and news owner",
"0x004010f0 near-city acquisition region scorer",
"0x00405920 same-company industry proximity aggregator",
"0x0041f6e0 center-cell token gate",
"0x0042b2d0 packed-u16 contains-key predicate",
"0x0047de00 linked-region resolver feeding 0x0040c990",
"0x004801a0 linked-transit route-anchor reachability gate",
"0x00425b90 pending-bonus/company-state gate",
"0x0040d360 region type/class filter",
"0x0040d540 weighted region-to-company proximity scorer",
"0x0040f6d0 subtype-1 placed-structure constructor",
"0x00481390 / 0x00480210 subtype-1 linked-site allocation and constructor",
"0x00444690 late world bring-up caller of 0x004133b0",
"0x004133b0 placed-structure local-runtime replay owner",
"0x0040e450 queued site-id cloned local-runtime replay helper",
"0x0040ee10 live-site position/scalar refresh helper",
"0x00480710 linked-site runtime side-buffer and route-entry-anchor refresh owner",
"0x0040df27 / 0x0040e00a / 0x0040edf6 linked-site side-refresh callers",
"0x004160aa non-bring-up runtime caller of 0x0040ee10",
"0x0048abc0 / 0x00493cf0 route-entry-anchor rebind and synthesis strip",
"0x0047dda0 linked-peer route-entry-anchor validator",
"0x00420030 / 0x00420280 peer-site boolean/selector pair",
"0x00406050 city-connection bonus/news sibling owner",
],
&[
"Direct disassembly now shows this branch iterating the live class-0 region collection, skipping regions with pending amount [region+0x276], reusing the center-cell token gate 0x0041f6e0 -> 0x0042b2d0, reusing the linked-region status branch 0x0047de00 -> 0x0040c990, checking candidate reachability through 0x004801a0, consulting the placed-structure peer-site boolean/selector pair 0x00420030 / 0x00420280 over 0x006cec20, scoring regions against company proximity and aging through 0x0040d540 and 0x0040cac0, and then publishing the winning linked company id from [region+0x2a4]. The peer-site selector seam itself is now grounded through the local helper strip: 0x0040cd70 seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268, 0x0040ceab and 0x0040d1a1 reach the save-backed 0x0045c150 / 0x0045c310 owner directly, that owner fills [owner+0x23e/+0x242] from tagged payload 0x5dc1, and 0x0045c36e then feeds [owner+0x23e] through 0x00456100 -> 0x00455b70 -> 0x0052edf0 into the live backing-record selector [site+0x04]. The remaining linked-site field work is now about which of those persisted site/peer lanes are actually sufficient for shellless acquisition and city-connection behavior, not about who owns [site+0x04].",
],
));
SmpPeriodicCompanyServiceTraceEntry {
company_id: entry.company_id,
name: entry.name.clone(),
active: entry.active,
linked_chairman_profile_id: entry.linked_chairman_profile_id,
preferred_locomotive_engine_type_raw_u8: entry
.preferred_locomotive_engine_type_raw_u8,
city_connection_latch: entry.city_connection_latch,
linked_transit_latch: entry.linked_transit_latch,
branches,
}
})
.collect::<Vec<_>>();
let mut notes = Vec::new();
notes.push(
"Periodic company service trace is intentionally an outer-owner probe: it reports save-owned branch inputs and blocker seams without serializing the full projected runtime reader state.".to_string(),
);
notes.push(
"Direct disassembly now narrows the acquisition-side sibling substantially: 0x004014b0 gates on the periodic outer owner, then iterates the live class-0 region collection at 0x62b26c, rejects regions with nonzero [region+0x276], filters the region-type lane through 0x0040d360, scores candidate regions against company linkage/age/proximity through 0x0040d540 and 0x0040cac0, and publishes the winning linked company id from [region+0x2a4] through the shared news lane 0x4554e0.".to_string(),
);
notes.push(
"The shellless acquisition frontier is narrower now too: the peer-site selector/linked-peer seam is grounded enough to plan around, and the company/chairman side already sits on existing runtime-backed stat-family and save-native roster inputs. The remaining blocker is region-side restore or rebuild ownership for [region+0x276], [region+0x2a4], and the cached tri-lane [region+0x310/+0x338/+0x360], plus the stable class/type discriminator consumed through 0x0040d360.".to_string(),
);
notes.push(
"Direct disassembly now tightens the remaining region lanes too: 0x00422100 itself writes the pending amount lane [region+0x276], so that field is no longer an unknown producer, only an ordinary-save restore gap; 0x0040cac0 is only the raw tri-lane delta reader over [region+0x310/+0x338/+0x360]; 0x0040d360 is only the exact type test [owner_vtable+0x80+0x32] == 4; and the current binary write scan finds no direct region-class runtime writer for either [region+0x2a4] or [region+0x310/+0x338/+0x360], which now makes both lanes look payload/restore-owned rather than service-produced.".to_string(),
);
notes.push(
"That branch also reuses the same peer-site helper strip already bounded under the city-connection family: 0x0041f6e0 resolves the current center world-grid cell and checks one packed token through 0x0042b2d0, 0x0047de00 follows the linked region behind the candidate site into the status byte returned by 0x0040c990, and 0x004801a0 checks whether one candidate site is reachable from the cached company route anchor through the pending-bonus companion path 0x00425b90 -> 0x00401860 -> 0x0048e3c0.".to_string(),
);
notes.push(
"Direct disassembly now closes the collection identity too: 0x00420030 is the boolean peer gate and 0x00420280 is the first-match selector over the live placed-structure / peer-site collection 0x006cec20, combining 0x0042b2d0, the optional linked-company filter through 0x0047efe0, the station-or-transit gate 0x0047fd50, and the linked-region status branch 0x0047de00 -> 0x0040c990.".to_string(),
);
notes.push(
"Direct disassembly now closes the negative persistence side too: the direct 0x36b1 per-record callbacks serialize the shared base scalar triplets rooted at [this+0x206/+0x20a/+0x20e] plus the subordinate payload callback strip, while the 0x4a9d/0x4a3a/0x4a3b side-buffer owner only persists route-entry lists, three byte arrays, five proximity buckets, and the sampled-cell list. That means neither checked-in save owner seam currently persists the core peer-site identity fields [site+0x04], [site+0x2a8], or [peer+0x08] directly.".to_string(),
);
notes.push(
"The replay strip is tighter now too. 0x00444690 is the current late world bring-up caller of 0x004133b0, that outer owner drains queued site ids through 0x0040e450 and then sweeps every live placed structure through 0x0040ee10, and 0x0040ee10 itself reaches 0x0040edf6 -> 0x00480710 plus the later 0x0040e360 follow-on. A separate runtime path at 0x004160aa also re-enters 0x0040ee10 later. So [peer+0x08] replay is no longer the open question, and [site+0x04] is no longer an owner mystery either: the local linked-site helper strip seeds [site+0x3cc/+0x3d0] from 0x62b2fc / 0x62b268, reaches the save-backed 0x0045c150 / 0x0045c310 owner directly, that owner fills [owner+0x23e/+0x242] from tagged payload 0x5dc1, and 0x0045c36e then feeds [owner+0x23e] through 0x00456100 -> 0x00455b70 -> 0x0052edf0 into [site+0x04]. The remaining non-hook target is now the smaller shellless-simulation question: which subset of those persisted site/peer fields is actually sufficient to run 0x004014b0 and its city-connection sibling without shell state.".to_string(),
);
SmpPeriodicCompanyServiceTraceReport {
profile_family,
selected_company_id,
world_issue_37_present,
world_finance_neighborhood_present,
region_record_body_present,
placed_structure_record_body_present,
infrastructure_asset_side_buffer_present,
peer_site_selector_candidate_owner_strip,
peer_site_selector_candidate_persisted_tag_hex,
peer_site_selector_candidate_selector_lane,
peer_site_selector_candidate_class_identity_status,
peer_site_selector_candidate_helper_linkage,
peer_site_restore_input_fields,
peer_site_runtime_input_fields,
peer_site_runtime_reconstruction_status,
peer_site_runtime_reconstruction_steps,
near_city_acquisition_region_input_fields,
near_city_acquisition_peer_input_fields,
near_city_acquisition_company_input_fields,
near_city_acquisition_shellless_readiness_status,
near_city_acquisition_runtime_backed_input_families,
near_city_acquisition_remaining_owner_gaps,
near_city_acquisition_region_lane_statuses,
atlas_candidate_consumers,
known_bridge_helpers,
next_owner_questions,
companies,
notes,
}
}
pub fn inspect_save_region_service_trace_file(
path: &Path,
) -> Result<SmpRegionServiceTraceReport, Box<dyn std::error::Error>> {
let analysis = inspect_save_company_and_chairman_analysis_file(path)?;
Ok(build_region_service_trace_report(&analysis))
}
pub fn inspect_save_infrastructure_asset_trace_file(
path: &Path,
) -> Result<SmpInfrastructureAssetTraceReport, Box<dyn std::error::Error>> {
let analysis = inspect_save_company_and_chairman_analysis_file(path)?;
Ok(build_infrastructure_asset_trace_report(&analysis))
}
fn build_region_service_trace_report(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> SmpRegionServiceTraceReport {
let atlas_candidate_consumers = vec![
"0x00422100 periodic class-0 region picker and queue seed owner".to_string(),
"0x004337c0 queued 0x20-byte notice-node append helper".to_string(),
"0x00437c00 queued-kind dispatch owner".to_string(),
"0x004c7520 kind-7 region-focused custom-modal owner".to_string(),
"0x004358d0 pending region bonus service owner".to_string(),
"0x00438710 recurring queued-notice service owner".to_string(),
"0x00420030 / 0x00420280 city-connection peer probes".to_string(),
"0x0047efe0 placed-structure linked-company resolver".to_string(),
];
let known_owner_bridge_fields = vec![
"[region+0x25e] pending-bonus severity/source lane".to_string(),
"[region+0x276] pending bonus amount".to_string(),
"[region+0x302] completion latch".to_string(),
"[region+0x316] one-shot fallback notice latch".to_string(),
"[region+0x356] localized region name".to_string(),
"[region+0x23a] world-scalar-backed region lane used in notices".to_string(),
];
let known_bridge_helpers = vec![
"0x004207d0 city_site_format_connection_bonus_status_label".to_string(),
"0x00420030 city_connection_bonus_exists_matching_peer_site".to_string(),
"0x00420280 city_connection_bonus_select_first_matching_peer_site".to_string(),
"0x0047efe0 placed_structure_query_linked_company_id".to_string(),
"0x00480bb0 placed_structure_refresh_linked_site_display_name_and_route_anchor".to_string(),
"0x00420650 city-site local scalar refresh release-side companion".to_string(),
"0x00421510 world_region_collection_refresh_records_from_tagged_bundle".to_string(),
"0x0041f5c0 world_region_load_tagged_payload_and_profile_collection_0x37f".to_string(),
"0x00455fc0 shared region tagged-payload reload companion".to_string(),
"0x00455870 region triplet-band tagged restore callback (world-region vtable +0x48)"
.to_string(),
"0x00455930 region triplet-band tagged serializer callback (world-region vtable +0x4c)"
.to_string(),
"0x004cc930 selected-region severity/source editor helper".to_string(),
"0x00438150 fixed-region severity/source reseed owner".to_string(),
"0x00442cc0 fixed-region severity/source clamp owner".to_string(),
];
let next_owner_questions = vec![
"Which restore seam re-seeds [region+0x25e] and clears [region+0x302/+0x316] before the grounded 0x00422100 -> 0x004358d0 producer/consumer cycle runs again?".to_string(),
"Which stable region id or class discriminator survives save/load strongly enough to drive 0x004358d0 after the class-0 raster/id rebuilds are ruled out?".to_string(),
"How far can the grounded 0x00420030/0x00420280 plus 0x0047efe0 connection chain be rehosted directly before the transient queued-notice family matters again?".to_string(),
];
let candidate_consumer_hypotheses = vec![
SmpServiceConsumerHypothesis {
label: "pending region bonus service path".to_string(),
status: if analysis.region_record_triplets.is_some() {
"highest_priority_static_mapping_target".to_string()
} else {
"possible_consumer_family".to_string()
},
candidate_consumers: vec![
"0x004358d0 pending region bonus service owner".to_string(),
"0x00420030 / 0x00420280 city-connection peer probes".to_string(),
"0x0047efe0 placed-structure linked-company resolver".to_string(),
],
evidence: vec![
"atlas already bounds this owner as the direct consumer of [region+0x276], [region+0x302], and [region+0x316]".to_string(),
"the new region trace already proves the record envelope and profile subcollection, so the remaining gap is the separate persisted latch seam rather than the service owner".to_string(),
"direct disassembly now shows 0x004358d0 calling 0x00420030 twice plus 0x00420280, resolving the linked company through 0x0047efe0, posting company stat slot 4, and then clearing [region+0x276] while stamping [region+0x302] or [region+0x316]".to_string(),
"that same direct disassembly now also tightens the branch meaning: the linked-company branch formats the localized region-name notice from [region+0x356], posts it through 0x004554e0 and 0x0042a080, clears [region+0x276], and stamps [region+0x302]=1, while the fallback branch only runs when [region+0x316]==0 and then flips that one-shot latch to 1 before emitting its alternate notice".to_string(),
"the checked-in constructor owner 0x00421200 now also proves these latches are initialized locally at record construction time, which narrows the remaining gap to post-construction restore or rebuild rather than basic field identity".to_string(),
],
blockers: vec![
"restore seam that re-seeds [region+0x25e] and clears [region+0x302/+0x316] between service cycles".to_string(),
"stable region id or class discriminator".to_string(),
],
},
SmpServiceConsumerHypothesis {
label: "region tagged-load restore path".to_string(),
status: if analysis.region_record_triplets.is_some() {
"parallel_static_mapping_target".to_string()
} else {
"possible_consumer_family".to_string()
},
candidate_consumers: vec![
"0x00421510 world_region_collection_refresh_records_from_tagged_bundle".to_string(),
"0x0041f5c0 world_region_load_tagged_payload_and_profile_collection_0x37f".to_string(),
"0x00455fc0 shared region tagged-payload reload companion".to_string(),
],
evidence: vec![
"the checked-in function map already grounds 0x00421510 as the tagged region-collection load owner that dispatches each live record through vtable slot +0x40".to_string(),
"the checked-in function map already grounds 0x0041f5c0 as the per-record load slot that reloads the tagged payload through 0x00455fc0 and then rebuilds profile collection [region+0x37f]".to_string(),
"constructor-side evidence now proves the latches are initialized locally, so the remaining gap can legitimately be framed as post-construction restore or rebuild".to_string(),
"direct disassembly of 0x0041f590/0x0041f5b0 now proves the world-region vtable root is 0x005c9a28, so the 0x00455fc0 dispatch at slot +0x48 lands on 0x00455870 and the serializer sibling at +0x4c lands on 0x00455930".to_string(),
"direct disassembly of 0x00455870/0x00455930 now shows that callback pair only restores and serializes two helper-local three-lane scalar bands: 0x00455870 reads six dwords through 0x531150 and forwards them to 0x530720 -> [helper+0x1e2/+0x1e6/+0x1ea] and 0x52e8b0 -> [helper+0x4b/+0x4f/+0x53], while 0x00455930 writes that same pair back through 0x531030; it still does not touch acquisition-side lanes [region+0x2a4] or [region+0x310/+0x338/+0x360]".to_string(),
"direct disassembly now tightens the rest of 0x00455fc0 too: after the +0x48 callback it only runs 0x0052ebd0 to read two one-byte generic flags through 0x531150 into base object bytes [this+0x20], [this+0x8d], [this+0x5c..+0x61], [this+0x1ee], [this+0x1fa], and [this+0x3e], then opens 0x55f3 only for span accounting before returning, so the missing region latches are not hiding in the remainder of 0x00455fc0 either".to_string(),
"direct disassembly of 0x00421510 now also shows the exact tagged loop shape: it opens 0x5209, reads 0x520a, iterates live entry ordinals through 0x518380/0x518140, seeds a stack-local world-region vtable helper through 0x0041f590/0x0041f5b0, dispatches each loaded record through slot +0x40, and only then closes 0x520b".to_string(),
"direct disassembly of 0x0041f5c0 now also shows its post-0x00455fc0 work is local to the profile collection path: it clamps [region+0x31b] back to 1.0f when needed, zeroes [region+0x317], allocates one 0x88-sized helper through 0x53b070/0x518b90, stores it at [region+0x37f], loads that helper through 0x518680, and clears [region+0x385] before returning".to_string(),
"the first caller-side checkpoint above 0x00421510 is now grounded too: 0x00444887 invokes the region collection refresh inside a broader restore sequence and then immediately advances to territory_collection_refresh_records_from_tagged_bundle 0x00487c20 and support_collection_refresh_records_from_tagged_bundle 0x0040b5d0, which makes the missing latches look like a later global rebuild seam rather than hidden work inside 0x00421510 itself".to_string(),
"that broader restore strip now also has one grounded later region-local sweep: at 0x00444b08 it re-enters the live region collection through 0x00421ce0, which walks live records via 0x518380/0x518140 and dispatches 0x0041fb00 per record".to_string(),
"the checked-in atlas already grounds 0x0041fb00 as the class-0-only default-region helper under the same family, and 0x00421730 as the later raster finalizer that repopulates [world+0x212d] from class-0 region ids".to_string(),
"direct disassembly now tightens that later sweep too: 0x0041fb00 exits immediately for nonzero [region+0x23e], while 0x00421730 clears the per-cell region word at [world+0x212d]+cell*4+1, seeds cached bounds-like fields [region+0x242/+0x246/+0x24a/+0x24e/+0x252], and only then enters the class-0 path that consumes [region+0x256] and the coordinate helpers 0x00455800/0x00455810".to_string(),
"the companion region-set root is runtime-owned now too: direct disassembly of the broader bring-up strip at 0x00448740..0x0044881f shows 0x006cfc9c being allocated through 0x53b070 and constructed through 0x00487bd0 before later rebuild passes run, so the 0x00487650/0x004881b0 companion path is operating on a runtime-owned helper collection rather than a hidden save-owned latch seam".to_string(),
"the later restore-band siblings are tighter now too: 0x00487de0 clears the prior chunked border queues through 0x00533cf0, builds a small per-region id map from [region+0x00]/[region+0x35] keyed by class [region+0x31], scans the live world raster at [world+0x2131], and appends fresh border-segment rows through 0x00536ea0 without touching [region+0x25e/+0x276/+0x302/+0x316]".to_string(),
"the neighboring world-grid reseed 0x0044c4b0 is tighter now too: it clears bit 0x10 across the live grid byte at cell offset +0xe6, then walks the live region collection at 0x0062bae0, admits only class-0 records via [region+0x23e], resolves one representative center cell through 0x00455f60, and marks that same bit back on, which again reads as raster presentation state rather than pending/completion latch restore".to_string(),
"the companion region-set rebuild above that border pass is narrower now too: 0x00487650 is only a small constructor wrapper over 0x00487540 that seeds [region+0x00] from the caller-supplied id, while 0x004881b0 rebuilds [region+0x3d] from the world raster histogram, zeroes [region+0x41], folds class-0 children back into parent [region+0x41] through [region+0x35], and then tails into the border emitter on 0x006cfc9c via 0x00487de0".to_string(),
"the later class-0 batch at 0x00438087 is narrower now too: it walks live class-0 regions through 0x0062bae0, scales the mirrored severity/source pair [region+0x25a/+0x25e] from the current value using world-side factors, clamps the result, and then hands the whole collection to 0x00421c20; it never reads or writes [region+0x276/+0x302/+0x316]".to_string(),
"the follow-on 0x00421c20 is now bounded as a parameterized region-collection helper rather than a latch owner: it loops the same collection with caller-provided scalar arguments, dispatches each record through 0x004235c0, and never touches the pending/completion/one-shot lanes directly".to_string(),
"the subsequent world follow-ons are narrower too: 0x00437b20 only stages one world-side reentry guard at [world+0x46c38], iterates the live region collection through 0x00423d30, and then tails into 0x00434d40, while 0x00437220 rebuilds broader world byte-set state around [world+0x66be/+0x69db] and other global collections. Those branches are still broader runtime follow-ons, not direct owners of [region+0x276/+0x302/+0x316]".to_string(),
],
blockers: vec![
"which later restore or rebuild owner rehydrates [region+0x276/+0x302/+0x316] after the 0x00421510 -> 0x0041f5c0 -> 0x00455fc0 path completes".to_string(),
"whether [region+0x25e] severity/source and any stable region id/class discriminator are serialized elsewhere in the tagged region body or recomputed later by another post-load owner after the 0x00421ce0 -> 0x0041fb00 -> 0x00421730 class-0 raster/id sweep, 0x004881b0 companion cell-count rebuild, 0x00487de0 border rebuild, 0x0044c4b0 center-cell reseed, the 0x00438087 mirrored severity/source batch, and the 0x00421c20 -> 0x004235c0 follow-on helper loop are all ruled out as latch owners".to_string(),
],
},
SmpServiceConsumerHypothesis {
label: "periodic producer and queued-notice path".to_string(),
status: "secondary_candidate_after_pending_service".to_string(),
candidate_consumers: vec![
"0x00422100 periodic class-0 region picker and queue seed owner".to_string(),
"0x004337c0 queued 0x20-byte notice-node append helper".to_string(),
"0x00438710 recurring queued-notice service owner".to_string(),
],
evidence: vec![
"atlas ties these owners to the transient kind-7 queue family rooted at [world+0x66a6]".to_string(),
"grounded save probes now show that the ordinary-save queue family is not obviously persisted, so this looks more like runtime rebuild state than a direct save seam".to_string(),
"direct disassembly now shows 0x00422100 itself owning the pending-amount seed: it counts eligible class-0 regions with [region+0x276]==0 and [region+0x302]==0, samples one candidate, buckets [region+0x25e] against three thresholds, writes the resulting amount to [region+0x276], and then appends the kind-7 queued notice through 0x004337c0".to_string(),
],
blockers: vec![
"transient queue is not obviously persisted in ordinary saves".to_string(),
"needs the upstream restore seam for [region+0x25e/+0x302/+0x316] rather than more queue-side probing".to_string(),
],
},
SmpServiceConsumerHypothesis {
label: "queued kind-7 modal dispatch path".to_string(),
status: "shell_adjacent_reference_only".to_string(),
candidate_consumers: vec![
"0x00437c00 queued-kind dispatch owner".to_string(),
"0x004c7520 kind-7 region-focused custom-modal owner".to_string(),
],
evidence: vec![
"atlas already bounds this family as the shell-facing modal dispatch above the queued region id".to_string(),
"it is still useful as a reference owner for field identity, but not the first shellless rehost target".to_string(),
],
blockers: vec![
"full shell/dialog ownership remains out of scope".to_string(),
],
},
];
let entries = analysis
.region_record_triplets
.as_ref()
.map(|probe| {
probe.entries
.iter()
.map(|entry| SmpRegionServiceTraceEntry {
name: entry.name.clone(),
profile_collection_count: entry
.profile_collection
.as_ref()
.map(|collection| collection.live_record_count),
policy_leading_f32_0_text: format!("{:.6}", entry.policy_leading_f32_0),
policy_leading_f32_1_text: format!("{:.6}", entry.policy_leading_f32_1),
policy_leading_f32_2_text: format!("{:.6}", entry.policy_leading_f32_2),
policy_reserved_dword_hex_words: entry
.policy_reserved_dwords
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
policy_trailing_word_hex: entry.policy_trailing_word_hex.clone(),
branches: vec![
build_service_trace_branch_status(
"pending_bonus_queue_seed",
"blocked_missing_pending_bonus_owner_lane",
&[
"region triplet envelope",
"embedded profile subcollection",
"policy float lanes",
],
&[
"[region+0x276] pending amount lane",
"[region+0x25e] severity/source lane",
],
&[
"0x00422100 periodic class-0 region picker and queue seed owner",
"0x004337c0 queued 0x20-byte notice-node append helper",
],
&["The queued kind-7 notice family is not obviously persisted in ordinary saves, so the pending queue must be treated as transient until a direct owner seam is found."],
),
build_service_trace_branch_status(
"city_connection_completion",
"blocked_missing_completion_and_one_shot_latches",
&[
"region triplet envelope",
"region name stem",
],
&[
"[region+0x302] completion latch",
"[region+0x316] one-shot notice latch",
"stable region id or class discriminator",
],
&[
"0x004358d0 pending region bonus service owner",
"0x00420030 / 0x00420280 city-connection peer probes",
"0x0047efe0 placed-structure linked-company resolver",
],
&["The remaining region blocker is a separate owner seam for the latches the city-connection branch reads and writes."],
),
],
})
.collect::<Vec<_>>()
})
.unwrap_or_default();
let mut notes = Vec::new();
notes.push(
"Region service trace treats the queued kind-7 notice family as transient runtime state until a persisted owner seam is found.".to_string(),
);
notes.push(
"Direct disassembly now grounds the core producer/consumer pair itself: 0x00422100 seeds [region+0x276] from the severity/source lane [region+0x25e] and appends the kind-7 notice through 0x004337c0, while 0x004358d0 consumes that amount, runs the city-connection peer probes 0x00420030/0x00420280 plus the linked-company resolver 0x0047efe0, and then stamps [region+0x302] or [region+0x316].".to_string(),
);
notes.push(
"Direct disassembly now also tightens the severity/source side itself: 0x004cc930 is a selected-region editor helper that writes [region+0x25a] and [region+0x25e] together from one integer input, while 0x00438150 and 0x00442cc0 are fixed-region global reseed/clamp owners over collection 0x0062bae0 that adjust the same mirrored pair for hardcoded region ids.".to_string(),
);
notes.push(
"Two more apparent offset hits are now ruled out as region false leads: 0x0043a5a0 is a separate constructor under vtable root 0x005ca078 that zeroes its own [this+0x302/+0x316] fields during local object setup, and 0x0045c460/0x0045c8xx is a separate vtable-0x005cb5e8 helper family whose [this+0x316] is a child-array pointer serialized through 0x61a9/0x61aa/0x61ab rather than a region latch.".to_string(),
);
notes.push(
"A direct-writer census now narrows the remaining literal offset path further: the other `0x302/0x316` writer bands at 0x0043dd45/0x0043de19/0x0043e0a7/0x0043f5bc all hang off the same non-region 0x005ca078 object family as 0x0043a5a0 through helpers 0x0043af60/0x0043b030, so the only grounded region-owned literal writes left are the constructor 0x00421200 plus the producer/consumer pair 0x00422100 and 0x004358d0.".to_string(),
);
notes.push(
"The later post-load per-region sweep is ruled down further now too: in the 0x00444887 restore strip, the follow-on loop at 0x00444b90 dispatches 0x00420560 over each live region, but that helper only zeroes and recomputes [region+0x312] from the embedded profile collection [region+0x37f]/[region+0x383] and lazily seeds the year-driven [region+0x317/+0x31b] band through 0x00420350, not [region+0x276/+0x302/+0x316].".to_string(),
);
notes.push(
"The current region seam is strong enough to prove record-envelope ownership, profile subcollection ownership, and the absence of hidden 0x55f3 tail padding on grounded saves.".to_string(),
);
if let Some(probe) = analysis.region_record_triplets.as_ref() {
let mut trailing_words = probe
.entries
.iter()
.map(|entry| entry.policy_trailing_word_hex.clone())
.collect::<Vec<_>>();
trailing_words.sort();
trailing_words.dedup();
let preview = trailing_words
.iter()
.take(4)
.cloned()
.collect::<Vec<_>>()
.join(", ");
notes.push(format!(
"Region 0x55f2 trailing-word candidates currently collapse to {} distinct value(s): {}.",
trailing_words.len(),
if preview.is_empty() {
"none".to_string()
} else {
preview
}
));
if probe.entries.iter().all(|entry| {
entry.policy_reserved_dwords.iter().all(|word| *word == 0)
&& entry.policy_trailing_word == 1
}) {
notes.push(
"Grounded region 0x55f2 fixed-policy chunks also keep all three reserved dwords at zero while the trailing word stays 0x0001, so that chunk is not currently carrying the missing latch/id discriminator."
.to_string(),
);
}
let pre_name_prefix_count = probe
.entries
.iter()
.filter(|entry| entry.pre_name_prefix_len != 0)
.count();
let unique_pre_name_prefix_lens = probe
.entries
.iter()
.map(|entry| entry.pre_name_prefix_len)
.collect::<BTreeSet<_>>()
.into_iter()
.collect::<Vec<_>>();
notes.push(format!(
"Grounded live-entry payload starts now also show {} of {} region records with nonzero bytes before the first 0x55f1 tag; unique pre-name prefix lengths are {:?}.",
pre_name_prefix_count,
probe.entries.len(),
unique_pre_name_prefix_lens
));
}
SmpRegionServiceTraceReport {
profile_family: analysis.profile_family.clone(),
region_collection_header_present: analysis.region_collection_header.is_some(),
region_record_triplet_count: analysis
.region_record_triplets
.as_ref()
.map(|probe| probe.record_count)
.unwrap_or_default(),
queued_notice_record_count: analysis
.region_queued_notice_records
.as_ref()
.map(|probe| probe.entries.len())
.unwrap_or_default(),
atlas_candidate_consumers,
known_owner_bridge_fields,
known_bridge_helpers,
next_owner_questions,
candidate_consumer_hypotheses,
entries,
notes,
}
}
fn build_infrastructure_asset_trace_report(
analysis: &SmpSaveCompanyChairmanAnalysisReport,
) -> SmpInfrastructureAssetTraceReport {
let side_buffer = analysis.placed_structure_dynamic_side_buffer.as_ref();
let alignment = analysis
.placed_structure_dynamic_side_buffer_alignment
.as_ref();
let name_pair_summaries = side_buffer
.map(|probe| probe.name_pair_summaries.as_slice())
.unwrap_or(&[]);
let bridge_like_name_pair_count = name_pair_summaries
.iter()
.filter(|summary| summary.primary_name.contains("Bridge"))
.count();
let tunnel_like_name_pair_count = name_pair_summaries
.iter()
.filter(|summary| summary.primary_name.contains("Tunnel"))
.count();
let track_cap_like_name_pair_count = name_pair_summaries
.iter()
.filter(|summary| summary.primary_name.contains("TrackCap"))
.count();
let st_only_name_pair_corpus = !name_pair_summaries.is_empty()
&& name_pair_summaries
.iter()
.all(|summary| summary.primary_name.contains("ST"))
&& !name_pair_summaries
.iter()
.any(|summary| summary.primary_name.contains("DT"));
let atlas_candidate_consumers = vec![
"0x00491c60 infrastructure tagged side-buffer serializer owner".to_string(),
"0x00493be0 infrastructure tagged side-buffer collection load owner".to_string(),
"0x004a2c80 infrastructure composition chooser owner (DT family)".to_string(),
"0x004a34e0 infrastructure composition chooser sibling (ST family)".to_string(),
"0x0048a1e0 infrastructure child attach helper".to_string(),
"0x0048dcf0 infrastructure tagged child-stream restore outer owner".to_string(),
"0x0048dd50 infrastructure child rebuild loop".to_string(),
"0x00490a3c infrastructure payload attach helper".to_string(),
"0x004559d0 infrastructure tagged string-triplet serializer".to_string(),
"0x00455870 infrastructure tagged string-triplet load companion".to_string(),
"0x00455930 infrastructure scalar-triplet serializer sibling".to_string(),
"0x00448a70 / 0x00493660 / 0x0048b660 route and world follow-on family".to_string(),
"0x004133b0 placed-structure local-runtime refresh outer owner".to_string(),
];
let known_owner_bridge_fields = vec![
"outer stream prelude [u16 child count, optional saved primary-child byte]".to_string(),
"[this+0x248] cached primary-child slot".to_string(),
"[this+0x206/+0x20a/+0x20e] route-entry resolver fields".to_string(),
"[this+0x1e2/+0x1e6/+0x1ea] published anchor triplet".to_string(),
"[this+0x4b/+0x4f/+0x53] companion local triplet lane".to_string(),
"child list [this+0x75] under the Infrastructure owner".to_string(),
"non-direct live-entry directory [collection+0x3c] with 12-byte rows (payload pointer, previous live id, next live id)".to_string(),
];
let known_bridge_helpers = vec![
"0x00493be0 tagged 0x38a5/0x38a6/0x38a7 collection load owner".to_string(),
"0x00491c60 tagged 0x38a5/0x38a6/0x38a7 collection serializer owner".to_string(),
"0x004a2c80/0x004a34e0 paired upstream infrastructure composition choosers with decoded DT/ST table families plus BallastCap/Overpass literals".to_string(),
"0x0048a340 infrastructure chooser selector setter for [0x226]/[0x219]/[0x251]/bit 0x20".to_string(),
"0x0048a6c0 per-entry serializer for outer child-count / primary-child prelude and child payload callbacks".to_string(),
"0x00490960 infrastructure child constructor / selector propagator".to_string(),
"0x00455a40 raw vtable slot +0x44 dispatch wrapper".to_string(),
"0x00455a50 raw vtable slot +0x40 dispatch wrapper with global bridge reset".to_string(),
"0x004559d0 tagged child payload serializer for 0x55f1/0x55f2/0x55f3".to_string(),
"0x00490200 infrastructure seeded-lane route/link comparator".to_string(),
"0x00518140 indexed_collection_resolve_live_entry_payload_pointer_by_live_id".to_string(),
"0x005181f0 indexed_collection_unlink_non_direct_live_entry".to_string(),
"0x00518260 indexed_collection_link_non_direct_live_entry".to_string(),
"0x00518380 indexed_collection_find_nth_live_entry_id".to_string(),
"0x00518680 indexed_collection_load_header_bitset_and_non_direct_tables".to_string(),
"0x005395d0 shared child-attach list owner".to_string(),
"0x00539530 shared position-lane seed helper".to_string(),
"0x0053a5b0 shared third position-lane seed helper".to_string(),
"0x0052e8b0 runtime_object_publish_companion_triplet_lane_4b_4f_53".to_string(),
"0x00530720 runtime_object_publish_anchor_triplet_and_optionally_rebind_world_cell_handle"
.to_string(),
"0x0048e140 / 0x0048e160 / 0x0048e180 route-entry resolver helpers".to_string(),
];
let next_owner_questions = vec![
"With 0x00491c60, 0x0048a6c0, 0x00490960, 0x00455a40, and 0x004559d0 now grounded as the full child-construction and write-side dispatch chain for the `0x38a5/0x38a6/0x38a7` family, how do the remaining compact-prefix regimes subdivide the already-mapped save-side mode families (0x0a BallastCap, 0x0b TrackCap, 0x02 Tunnel, 0x01 Bridge, with 0x03 Overpass only grounded statically) before they surface in the seeded lanes [this+0x206/+0x20a/+0x20e], the slot +0x4c serializer, and the trailing 0x52ec50 footer path?".to_string(),
"Inside the grounded overpass/ballast branch ([this+0x226]==3) of the paired chooser siblings, when do the fixed BallastCap and Overpass literals (0x5cb138/0x5cb150 and 0x5cb168/0x5cb180) fire, and does the pure BallastCap class 0x0055/0x00 stay a boundary artifact or become a real outer prelude consumed by 0x0048dcf0?".to_string(),
"Which 0x38a5 embedded name-pair groups survive into the per-child vtable +0x40 payload callbacks dispatched through 0x00455a50?".to_string(),
"After the direct route-entry bridge helpers over [this+0x206/+0x20a/+0x20e] are grounded, which later route/local-runtime owner above 0x00448a70/0x00493660/0x0048b660 still depends on the remaining mixed exact classes once [this+0x248] is demoted to child-list cache/cleanup state?".to_string(),
];
let candidate_consumer_hypotheses = vec![
SmpServiceConsumerHypothesis {
label: "infrastructure child attach/rebuild path".to_string(),
status: if side_buffer.is_some() && (bridge_like_name_pair_count > 0
|| tunnel_like_name_pair_count > 0
|| track_cap_like_name_pair_count > 0)
{
"highest_priority_static_mapping_target".to_string()
} else {
"possible_consumer_family".to_string()
},
candidate_consumers: vec![
"0x00493be0 infrastructure tagged side-buffer collection load owner".to_string(),
"0x0048a1e0 infrastructure child attach helper".to_string(),
"0x0048dcf0 infrastructure tagged child-stream restore outer owner".to_string(),
"0x0048dd50 infrastructure child rebuild loop".to_string(),
"0x00490a3c infrastructure payload attach helper".to_string(),
],
evidence: vec![
format!(
"real side-buffer name families currently count bridge/tunnel/track-cap pairs as {}/{}/{}",
bridge_like_name_pair_count,
tunnel_like_name_pair_count,
track_cap_like_name_pair_count
),
"atlas already bounds these helpers under the literal Infrastructure owner".to_string(),
"the side-buffer corpus is disjoint from the placed-structure triplet corpus, so a separate child/rebuild family is more plausible than a compact alias".to_string(),
"direct disassembly now shows 0x00493be0 opening tag family 0x38a5/0x38a6/0x38a7, reading one shared dword into the owner-local 0x90/0x94 lane, iterating each live collection entry, and dispatching every loaded infrastructure record through 0x0048dcf0 before the later follow-on owners run".to_string(),
"direct disassembly now also shows 0x00491c60 as the serializer sibling of 0x00493be0: it writes tags 0x38a5/0x38a6/0x38a7, serializes the shared owner-local dword from [this+0x90], iterates live entries through 0x00518380/0x00518140, and dispatches each entry to 0x0048a6c0".to_string(),
"direct disassembly now also grounds paired upstream chooser siblings: 0x004a2c80 routes the DT family and 0x004a34e0 routes the ST family, with both repeatedly calling 0x0048a1e0 and branching on child type codes at [this+0x226], selector bytes at [this+0x219]/[this+0x251]/[this+0x252], bit 0x20 in [this+0x24c], and follow-on owners 0x0048a340/0x0048f4c0/0x00490200/0x00490960".to_string(),
"direct disassembly now also shows 0x0048a6c0 serializing the outer per-record prelude directly: it writes the current child count as a u16, writes the saved primary-child ordinal byte derived from [this+0x248], and then serializes each child through 0x00455a40".to_string(),
"local .rdata at 0x005cfd00 now also proves the missing write-side slot directly: for Infrastructure children, 0x00455a40 lands on vtable slot +0x44 = 0x004559d0, alongside +0x40 = 0x00455fc0, +0x48 = 0x00455870, and +0x4c = 0x00455930".to_string(),
"direct disassembly now also shows 0x004559d0 writing 0x55f1, serializing the three string lanes [this+0x206/+0x20a/+0x20e], writing 0x55f2, dispatching slot +0x4c, re-entering 0x52ec50, and then writing the closing 0x55f3 tag".to_string(),
"direct disassembly now also shows the paired chooser siblings calling 0x00490960 directly on the child-construction side, alongside 0x0048a340, 0x0048f4c0, and 0x00490200".to_string(),
"direct disassembly now also shows 0x00490960 copying selector fields into the child object ([this+0x219], [this+0x251], bit 0x20 in [this+0x24c], and [this+0x226]), allocating a fresh 0x23a Infrastructure child, seeding it through 0x00455b70 with caller-supplied stem input plus fixed literal Infrastructure at 0x005cfd74, attaching it through 0x005395d0, seeding position lanes through 0x00539530/0x0053a5b0, and optionally caching it as primary child in [this+0x248]".to_string(),
"the currently grounded direct-constructor chooser branches are narrower now too: the repeated calls at 0x004a2eba/0x004a30f9/0x004a339c feed 0x00490960 with mode arg 0x0a and stem arg 0x005cb138 = BallastCapDT_Cap.3dp, so they bypass the selector-copy block at 0x004909e2 and go straight into fresh child allocation/seeding".to_string(),
"the wider direct-calls sweep now also grounds stable 0x00490960 mode families: mode 0x0b pairs with fixed TrackCapDT/ST_Cap literals at 0x0048ed01/0x0048ed20, mode 0x03 with OverpassST_section at 0x00495a44, mode 0x02 with the decoded TunnelST/TunnelDT tables and zero-stem fallbacks across 0x004a17eb/0x004a1995/0x004a1b44/0x004a1b7d/0x004a1b95, and mode 0x01 with the decoded BridgeDT/BridgeST tables plus bridge zero-stem fallbacks across 0x004a1dae/0x004a2043/0x004a2082/0x004a221e/0x004a22a5/0x004a23aa/0x004a23eb/0x004a2409/0x004a24f6".to_string(),
"objdump on 0x00490960 now also sharpens the source-side comparison for the remaining mixed exact-prefix classes: mode lives at [esp+0x10], stem at [esp+0x14], args 3/4 at [esp+0x18]/[esp+0x1c] feed 0x539530, arg 5 at [esp+0x20] feeds 0x53a5b0, arg 10 at [esp+0x34] gates whether the new child is cached into [this+0x248], and the selector-copy block at 0x004909e2..0x00490a32 reads bytes from [esp+0x28]/[esp+0x2c]/[esp+0x30] into [this+0x219]/[this+0x251]/bit0x20 in [this+0x24c]. The fixed TrackCap mode-0x0b branches at 0x0048ed01/0x0048ed20 push literals 0x005cb198/0x005cb1ac after the same pre-seeded 1,-1,-1,0,0 flag bundle, so they reach 0x490960 with arg7/arg8/arg9 = -1/-1/0 and bypass that selector-copy block because mode >= 4. The tunnel mode-0x02 family at 0x004a17eb/0x004a1995/0x004a1b44/0x004a1b7d plus zero-stem fallback 0x004a1b95 necessarily flows through the selector-copy block because mode < 4, and the objdump caller bundles show those branches reaching 0x490960 with arg8 fixed at 1, arg9 fixed at 0, and only arg7 varying through the branch-local register (ebx/ebp) before the table or fallback stem is pushed".to_string(),
"direct disassembly now also makes that tunnel-versus-track-cap residue more exact: 0x004a17eb/0x004a1995 drive mode-0x02 through TunnelDT/TunnelST tables 0x621a94/0x621a64 with arg7 entering as a one-bit selector (0 or 1) after the local sbb/inc pair; 0x004a1b44/0x004a1b7d repeat the same one-bit arg7 pattern through sibling tables 0x621a9c/0x621a6c; and the fallback 0x004a1b95 clears both stem and selector bundle entirely. By contrast, 0x0048ed01/0x0048ed20 reach mode-0x0b with the exact same 1,-1,-1,0,0 bundle and differ only by the pushed stem literal 0x005cb198 versus 0x005cb1ac.".to_string(),
"objdump on 0x00455b70 now also makes the shared child seed strip concrete: after zeroing the same [this+0x206/+0x20a/+0x20e] lanes, it copies stack args 1/2/3 into them through 0x51d820 whenever those args are non-null, so the 0x490960 call pattern seeds [0x206] from fixed payload literal 0x005c87a8, [0x20a] from the caller stem, and [0x20e] from fixed literal 0x005cfd74 = \"Infrastructure\" before 0x004559d0 later serializes those same three lanes".to_string(),
"objdump on 0x51d820 now also shows those seeded lanes are owned heap strings, not encoded ids: it frees any prior pointer through 0x5a1145, counts the incoming NUL-terminated ASCII bytes, allocates a fresh buffer through 0x5a125d, and copies the source string byte-for-byte into the destination slot".to_string(),
"objdump on 0x52ec50 now also makes the short footer bytes literal: it serializes one byte from bit 5 of [this+0x20] and one byte from bit 6 of [this+0x20] through 0x531030, so the residual compact-prefix ambiguity still lives in how those footer bits compose with the next-record prelude rather than in the seeded name lanes themselves".to_string(),
"direct disassembly now also grounds one concrete consumer strip below those footer bits: 0x00528d90 only admits the child when the explicit caller override is set, the surrounding global override byte [owner+0x3692] is set, or bit 0x20 in [child+0x20] is set; the sibling loop at 0x00529730 only takes the later 0x530280 follow-on when bit 0x40 in [child+0x20] is set".to_string(),
"that footer-bit consumer strip is tied to a broader higher-layer owner family now too: the same 0x005295f0..0x005297b7 loop repopulates a candidate cell set through 0x00533ba0, walks candidate child lists through 0x00556ef0/0x00556f00, and honors the same controller mode byte [owner+0x3692] that the checked-in atlas already ties to the world-window presentation dispatcher. So the remaining bit-0x20 question belongs to that nearby-presentation/controller family rather than to a free-floating serializer flag".to_string(),
"the neighboring helpers tighten that owner family further: atlas-backed 0x00533ba0 is the nearby-presentation cell-table helper under the layout/presenter strip, direct disassembly shows 0x00548da0 walking list root [layout+0x2593], and direct disassembly of 0x0054bab0 mutates layout slots [layout+0x2637/+0x263b/+0x2643]. That means the 0x005295f0..0x005297b7 footer-bit consumer is sitting in layout/presentation state, not in a simulation-owned infrastructure service".to_string(),
"objdump on 0x531030/0x5a464d/0x5a44a8 now also shows the infrastructure writer is not hiding another per-owner transform there: 0x531030 just forwards the caller-supplied pointer and byte count into the generic stream backend, and 0x5a44a8 is the shared chunked stream write path keyed by the stream handle rather than an infrastructure-specific encoder".to_string(),
"that caller-matrix split now rules out one easy explanation for the mixed save-side prefixes: the shared 0xff0000ff/0x0001/0xff class cannot come from selector-copy state alone, because its dominant TrackCap rows come from mode-0x0b callers that bypass selector-copy entirely while the tunnel residue comes from mode-0x02 callers that necessarily flow through it".to_string(),
"the current grounded q.gms side-buffer name corpus now maps directly onto those constructor families too: BridgeSTWood_Section.3dp aligns with mode 0x01 Bridge, TunnelSTBrick_Cap/Section.3dp with mode 0x02 Tunnel, BallastCapST_Cap.3dp with mode 0x0a BallastCap, and TrackCapST_Cap.3dp with mode 0x0b TrackCap; only the Overpass mode-0x03 family remains static-only in the current save corpus".to_string(),
"direct disassembly now also shows 0x00490200 reading the seeded lanes [this+0x206/+0x20a/+0x20e] back through the live route collection at 0x006cfca8, classifying peer relationships with [this+0x216/+0x218/+0x201/+0x202], and therefore acting as a route/link comparator above the same child payload fields that 0x004559d0 later serializes".to_string(),
"the direct route-entry bridge is tighter now too: 0x0048e140/0x0048e160/0x0048e180 simply resolve [this+0x206/+0x20a/+0x20e] through the live route collection at 0x006cfca8 and return the pointed route-entry or null, while 0x0048e1a0 walks the first two seeded lanes, resolves each peer route, and compares [peer+0x20e]/[peer+0x201] plus conditional [peer+0x206]/[peer+0x20a] against [this+0x202] before returning a boolean match".to_string(),
"the neighboring cached-primary-child path is narrower now too: 0x0048ed30 reads [this+0x248], walks child list [this+0x08] through 0x556ef0/0x556fa0, clears [this+0x248] when it matches the current child, destroys the child through 0x455d20/0x455650/0x53b080, and tears the list down through 0x556f20/0x5570b0/0x5571d0. That makes [this+0x248] a child-list cache and cleanup lane rather than the first route-entry bridge.".to_string(),
"the chooser tables now decode to concrete asset families too: 0x621a44/0x621a54 feed BridgeST caps/sections, 0x621a64 feeds TunnelST cap/section variants, 0x621a74/0x621a84 feed BridgeDT caps/sections, and 0x621a94 feeds TunnelDT variants; fixed literals 0x5cb138/0x5cb150 are BallastCapDT/ST and 0x5cb168/0x5cb180 are OverpassDT/ST".to_string(),
"the top-level chooser branches are grounded now too: [this+0x226]==1 routes bridge families, [this+0x226]==2 routes tunnel families, [this+0x226]==3 routes overpass/ballast families, and bit 0x20 in [this+0x24c] selects the cap-oriented side over the section-oriented side inside those DT/ST siblings".to_string(),
"direct disassembly now also shows 0x0048a340 as the exact chooser-state setter: its dword argument writes [this+0x226], its next two byte arguments write [this+0x219] and [this+0x251], and its final byte argument toggles bit 0x20 in [this+0x24c]".to_string(),
"the material selectors are grounded now too: in the bridge branch, [this+0x219] indexes Steel/Stone/Wood tables directly while value 2 takes the special suspension-cap path through [this+0x252]; in the tunnel branch, [this+0x251] selects Brick versus Concrete while the cap/section split comes from bit 0x20 choosing the base versus +0x8 table entry".to_string(),
"the [this+0x252] selector is partially grounded now too: when [this+0x219]==2, the chooser jump tables dispatch fixed BridgeDT/BridgeST suspension-cap literals for R10, L10, 12, 14, 16, and 18 variants instead of using the general Bridge* table families".to_string(),
side_buffer
.and_then(|probe| probe.first_record_child_count_after_owner_shared)
.map(|child_count| {
format!(
"grounded q.gms bytes now also show the first 0x38a6 record starting immediately after that shared dword with child_count={}, saved_primary_child_byte={}, and first 0x55f1 at offset +0x{:x}",
child_count,
side_buffer
.and_then(|probe| {
probe.first_record_saved_primary_child_byte_after_owner_shared_hex
.as_deref()
})
.unwrap_or("0x00"),
side_buffer
.and_then(|probe| {
probe.first_record_first_name_tag_relative_offset_after_owner_shared
})
.unwrap_or_default()
)
})
.unwrap_or_else(|| {
"no grounded first-record prelude summary was available after the shared 0x38a6 owner dword".to_string()
}),
"direct disassembly now shows 0x00518140 resolving a non-direct live entry through the tombstone bitset and then returning the first dword of a 12-byte row from [collection+0x3c] for the 0x38a5 path".to_string(),
"direct disassembly now also shows 0x005181f0/0x00518260 treating the same 12-byte rows as a live-entry directory: dword +0 is the payload pointer, dword +4 is previous live id, and dword +8 is next live id, with collection head/tail caches alongside them".to_string(),
"direct disassembly now also shows 0x00493be0 iterating live-entry ordinals through 0x00518380(ordinal, 0), converting each ordinal to a live id, then resolving that live id through 0x00518140 before handing the resulting payload pointer to 0x0048dcf0".to_string(),
"direct disassembly now shows 0x00518680 loading the non-direct collection header, tombstone bitset, and live-id-bound-scaled 12-byte tables for the non-direct path before 0x00493be0 starts iterating".to_string(),
"direct disassembly now also shows the shared child payload callback 0x00455fc0 opening 0x55f1, parsing three len-prefixed strings through 0x531380, opening 0x55f2, seeding the child through 0x455b70, dispatching slot +0x48, and then opening 0x55f3".to_string(),
"direct disassembly now also shows 0x00455b70 storing those three payload strings into [this+0x206/+0x20a/+0x20e], defaulting the second lane through a fixed literal when absent and defaulting the third lane back to the first string when absent".to_string(),
format!(
"current save-side probe reports {} embedded 0x55f1 rows with a third decoded string",
side_buffer
.map(|probe| probe.decoded_embedded_name_row_with_tertiary_name_count)
.unwrap_or_default()
),
format!(
"current save-side probe also reports {} complete 0x55f1/0x55f2/0x55f3 envelopes, dominant 0x55f2 chunk len 0x{:x}, and dominant 0x55f3 span 0x{:x}",
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
.unwrap_or_default(),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.dominant_policy_chunk_len)
.unwrap_or_default(),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.dominant_profile_chunk_len)
.unwrap_or_default()
),
"direct disassembly now also shows the post-+0x48 helper pair 0x52ebd0/0x52ec50 loading and serializing two single-byte lanes around the trailing 0x55f3 tag while folding them into bits 0x20 and 0x40 of [this+0x20]".to_string(),
format!(
"current save-side probe reports {} rows with the short 0x06-byte trailing span; dominant short flag pair is {}/{} x{}",
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref())
.map(|summary| summary.row_count_with_0x06_profile_span)
.unwrap_or_default(),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref())
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.first_flag_byte_hex.as_str())
.unwrap_or("0x00"),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref())
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.second_flag_byte_hex.as_str())
.unwrap_or("0x00"),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref())
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.count)
.unwrap_or_default()
),
"direct disassembly now also shows 0x455870 consuming six 4-byte lanes from the fixed 0x55f2 chunk and forwarding them into 0x530720 then 0x52e8b0, while 0x455930 serializes the same six dword lanes back through 0x531030".to_string(),
format!(
"current save-side probe reports {} fixed 0x1a policy rows; dominant trailing word is {} x{}",
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.fixed_policy_summary.as_ref())
.map(|summary| summary.row_count_with_0x1a_policy_chunk)
.unwrap_or_default(),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.fixed_policy_summary.as_ref())
.and_then(|summary| summary.dominant_trailing_word_hex.as_deref())
.unwrap_or("0x0000"),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.fixed_policy_summary.as_ref())
.map(|summary| summary.dominant_trailing_word_count)
.unwrap_or_default()
),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.fixed_policy_summary.as_ref())
.and_then(|summary| {
summary.compact_prefix_correlations.iter().find(|entry| {
entry.prefix_leading_dword == 0xff00_00ff
&& entry.prefix_trailing_word == 0x0001
&& entry.prefix_separator_byte == 0xff
})
})
.map(|correlation| {
format!(
"the fixed 0x55f2 lane for exact 0xff0000ff/0x0001/0xff is now explicit too: unique policy tuples={}, dominant mode={:?} x{}, dominant tuple=({:?} | {:?} | {:?}) x{}, and sample rows={:?}",
correlation.unique_policy_tuple_count,
correlation.dominant_mode_family,
correlation.dominant_mode_family_count,
correlation.dominant_first_triplet_dwords_hex,
correlation.dominant_second_triplet_dwords_hex,
correlation.dominant_trailing_word_hex,
correlation.dominant_policy_tuple_count,
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no fixed-policy compact-prefix correlation was available for 0xff0000ff/0x0001/0xff".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.fixed_policy_summary.as_ref())
.and_then(|summary| {
summary.compact_prefix_correlations.iter().find(|entry| {
entry.prefix_leading_dword == 0x0000_55f3
&& entry.prefix_trailing_word == 0x0001
&& entry.prefix_separator_byte == 0xff
})
})
.map(|correlation| {
format!(
"the fixed 0x55f2 lane for exact 0x000055f3/0x0001/0xff is now explicit too: unique policy tuples={}, dominant mode={:?} x{}, dominant tuple=({:?} | {:?} | {:?}) x{}, and sample rows={:?}",
correlation.unique_policy_tuple_count,
correlation.dominant_mode_family,
correlation.dominant_mode_family_count,
correlation.dominant_first_triplet_dwords_hex,
correlation.dominant_second_triplet_dwords_hex,
correlation.dominant_trailing_word_hex,
correlation.dominant_policy_tuple_count,
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no fixed-policy compact-prefix correlation was available for 0x000055f3/0x0001/0xff".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.dominant_profile_span_class_summary.as_ref())
.map(|summary| {
format!(
"the dominant 0x{:x}-byte post-profile class is now narrowed too: dominant name pair is {:?}/{:?} x{}, dominant compact prefix is {}/{}/{} x{}, and dominant prelude candidate is {}/{} x{} across {} rows",
summary.profile_chunk_len_to_next_name_or_end,
summary.dominant_primary_name,
summary.dominant_secondary_name,
summary.dominant_name_pair_count,
summary
.dominant_prefix_leading_dword_hex
.as_deref()
.unwrap_or("0x00000000"),
summary
.dominant_prefix_trailing_word_hex
.as_deref()
.unwrap_or("0x0000"),
summary
.dominant_prefix_separator_byte_hex
.as_deref()
.unwrap_or("0x00"),
summary.dominant_prefix_count,
summary
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
summary
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
summary
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
summary.row_count
)
})
.unwrap_or_else(|| {
"no dominant post-profile class summary was available for the embedded 0x55f3 spans".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.dominant_profile_span_class_summary.as_ref())
.map(|summary| {
format!(
"the dominant post-profile outliers are now explicit too: name-pair counts={:?}, compact-prefix counts={:?}, candidate-pattern counts={:?}",
summary
.name_pair_summaries
.iter()
.map(|entry| format!(
"{:?}/{:?}:{}",
entry.primary_name, entry.secondary_name, entry.count
))
.collect::<Vec<_>>(),
summary
.compact_prefix_pattern_summaries
.iter()
.map(|entry| format!(
"{}/{}/{}:{}",
entry.prefix_leading_dword_hex,
entry.prefix_trailing_word_hex,
entry.prefix_separator_byte_hex,
entry.count
))
.collect::<Vec<_>>(),
summary
.candidate_pattern_summaries
.iter()
.map(|entry| format!(
"{}/{}:{}",
entry.child_count_candidate_hex,
entry.saved_primary_child_byte_candidate_hex,
entry.count
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no dominant post-profile outlier breakdown was available".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.map(|summary| {
format!(
"candidate-pattern correlations now split the remaining prelude classes cleanly too: {:?}",
summary
.candidate_pattern_correlations
.iter()
.map(|entry| format!(
"{}/{} rows={} dominant-name={:?}/{:?} x{} dominant-prev-span={:?} x{}",
entry.child_count_candidate_hex,
entry.saved_primary_child_byte_candidate_hex,
entry.row_count,
entry.dominant_primary_name,
entry.dominant_secondary_name,
entry.dominant_name_pair_count,
entry.dominant_profile_span,
entry.dominant_profile_span_count
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no candidate-pattern correlation summary was available".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.map(|summary| {
format!(
"mode-family correlations now also split the candidate patterns directly: {:?}",
summary
.candidate_pattern_correlations
.iter()
.map(|entry| format!(
"{}/{} rows={} dominant-mode={:?} x{} mode-counts={:?}",
entry.child_count_candidate_hex,
entry.saved_primary_child_byte_candidate_hex,
entry.row_count,
entry.dominant_mode_family,
entry.dominant_mode_family_count,
entry
.mode_family_counts
.iter()
.map(|mode| format!(
"{}:{}",
mode.mode_family, mode.count
))
.collect::<Vec<_>>()
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no mode-family correlation summary was available for the prelude candidates".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.map(|summary| {
format!(
"profile-span mode-family correlations now also split the previous 0x55f3 spans directly: {:?}",
summary
.profile_span_correlations
.iter()
.map(|entry| format!(
"span=0x{:x} rows={} dominant-mode={:?} x{} mode-counts={:?}",
entry.previous_profile_chunk_len_to_next_name_or_end,
entry.row_count,
entry.dominant_mode_family,
entry.dominant_mode_family_count,
entry
.mode_family_counts
.iter()
.map(|mode| format!(
"{}:{}",
mode.mode_family, mode.count
))
.collect::<Vec<_>>()
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no profile-span mode-family correlation summary was available".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.map(|summary| {
format!(
"exact compact-prefix correlations now split the residual prelude classes directly: {:?}",
summary
.compact_prefix_correlations
.iter()
.map(|entry| format!(
"{}/{}/{} rows={} dominant-name={:?}/{:?} x{} dominant-span={:?} x{} dominant-candidate={:?} dominant-mode={:?} x{}",
entry.prefix_leading_dword_hex,
entry.prefix_trailing_word_hex,
entry.prefix_separator_byte_hex,
entry.row_count,
entry.dominant_primary_name,
entry.dominant_secondary_name,
entry.dominant_name_pair_count,
entry.dominant_profile_span,
entry.dominant_profile_span_count,
entry
.dominant_candidate_pattern
.as_ref()
.map(|pattern| format!(
"{}/{}:{}",
pattern.child_count_candidate_hex,
pattern.saved_primary_child_byte_candidate_hex,
pattern.count
)),
entry.dominant_mode_family,
entry.dominant_mode_family_count
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no compact-prefix correlation summary was available for the prelude candidates".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary.candidate_pattern_correlations.iter().find(|entry| {
entry.child_count_candidate == 2
&& entry.saved_primary_child_byte_candidate == 0xff
&& entry.dominant_primary_name.as_deref()
== Some("BridgeSTWood_Section.3dp")
&& entry.dominant_secondary_name.as_deref()
== Some("Infrastructure")
})
})
.map(|correlation| {
format!(
"the bridge-only two-child class is now grounded save-side too: candidate pattern {}/{} spans {} rows, stays pure {:?}/{:?}, and the dominant prior profile span is {:?} x{}",
correlation.child_count_candidate_hex,
correlation.saved_primary_child_byte_candidate_hex,
correlation.row_count,
correlation.dominant_primary_name,
correlation.dominant_secondary_name,
correlation.dominant_profile_span,
correlation.dominant_profile_span_count
)
})
.unwrap_or_else(|| {
"no grounded pure bridge-only two-child candidate class was available in the prelude correlations".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary
.profile_span_correlations
.iter()
.find(|row| row.previous_profile_chunk_len_to_next_name_or_end == 3)
})
.map(|correlation| {
format!(
"current save-side probe now also shows the short 0x03-byte post-profile gaps collapsing cleanly to the next-record prelude: dominant candidate pattern is {}/{} x{} across {} rows, mode counts={:?}, prefix counts={:?}",
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
correlation.row_count,
correlation
.mode_family_counts
.iter()
.map(|mode| format!("{}:{}", mode.mode_family, mode.count))
.collect::<Vec<_>>(),
correlation
.compact_prefix_pattern_summaries
.iter()
.map(|prefix| format!(
"{}/{}/{}:{}",
prefix.prefix_leading_dword_hex,
prefix.prefix_trailing_word_hex,
prefix.prefix_separator_byte_hex,
prefix.count
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no grounded 0x03-byte post-profile span correlation was available for the prelude candidates".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary.compact_prefix_correlations.iter().find(|entry| {
entry.prefix_leading_dword == 0xff00_00ff
&& entry.prefix_trailing_word == 0x0001
&& entry.prefix_separator_byte == 0xff
})
})
.map(|correlation| {
format!(
"the exact 0xff0000ff/0x0001/0xff compact-prefix class is now explicit: dominant name={:?}/{:?} x{}, dominant span={:?} x{}, dominant prelude={}/{} x{}, mode counts={:?}, name-pair counts={:?}, span counts={:?}, previous short-flag pairs={:?} across {} rows, and sample rows={:?}",
correlation.dominant_primary_name,
correlation.dominant_secondary_name,
correlation.dominant_name_pair_count,
correlation.dominant_profile_span,
correlation.dominant_profile_span_count,
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
correlation
.mode_family_counts
.iter()
.map(|mode| format!("{}:{}", mode.mode_family, mode.count))
.collect::<Vec<_>>(),
correlation
.name_pair_summaries
.iter()
.map(|entry| format!(
"{:?}/{:?}:{}",
entry.primary_name, entry.secondary_name, entry.count
))
.collect::<Vec<_>>(),
correlation
.profile_span_counts
.iter()
.map(|entry| format!(
"0x{:x}:{}",
entry.previous_profile_chunk_len_to_next_name_or_end,
entry.count
))
.collect::<Vec<_>>(),
correlation
.previous_short_profile_flag_pair_counts
.iter()
.map(|entry| format!(
"{}/{}:{}",
entry.first_flag_byte_hex,
entry.second_flag_byte_hex,
entry.count
))
.collect::<Vec<_>>(),
correlation.rows_with_previous_short_profile_flag_pair,
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no grounded 0xff0000ff/0x0001/0xff compact-prefix correlation was available".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary.compact_prefix_correlations.iter().find(|entry| {
entry.prefix_leading_dword == 0x0000_55f3
&& entry.prefix_trailing_word == 0x0001
&& entry.prefix_separator_byte == 0xff
})
})
.map(|correlation| {
format!(
"the exact 0x000055f3/0x0001/0xff compact-prefix class is now explicit too: dominant name={:?}/{:?} x{}, dominant span={:?} x{}, dominant prelude={}/{} x{}, mode counts={:?}, name-pair counts={:?}, previous short-flag pairs={:?} across {} rows, and sample rows={:?}",
correlation.dominant_primary_name,
correlation.dominant_secondary_name,
correlation.dominant_name_pair_count,
correlation.dominant_profile_span,
correlation.dominant_profile_span_count,
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
correlation
.mode_family_counts
.iter()
.map(|mode| format!("{}:{}", mode.mode_family, mode.count))
.collect::<Vec<_>>(),
correlation
.name_pair_summaries
.iter()
.map(|entry| format!(
"{:?}/{:?}:{}",
entry.primary_name, entry.secondary_name, entry.count
))
.collect::<Vec<_>>(),
correlation
.previous_short_profile_flag_pair_counts
.iter()
.map(|entry| format!(
"{}/{}:{}",
entry.first_flag_byte_hex,
entry.second_flag_byte_hex,
entry.count
))
.collect::<Vec<_>>(),
correlation.rows_with_previous_short_profile_flag_pair,
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no grounded 0x000055f3/0x0001/0xff compact-prefix correlation was available".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary.compact_prefix_correlations.iter().find(|entry| {
entry.prefix_leading_dword == 0xff00_00ff
&& entry.prefix_trailing_word == 0x0002
&& entry.prefix_separator_byte == 0xff
})
})
.map(|correlation| {
format!(
"the exact 0xff0000ff/0x0002/0xff compact-prefix class is now explicit too: dominant name={:?}/{:?} x{}, dominant span={:?} x{}, dominant prelude={}/{} x{}, mode counts={:?}, span counts={:?}, and sample rows={:?}",
correlation.dominant_primary_name,
correlation.dominant_secondary_name,
correlation.dominant_name_pair_count,
correlation.dominant_profile_span,
correlation.dominant_profile_span_count,
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
correlation
.mode_family_counts
.iter()
.map(|mode| format!("{}:{}", mode.mode_family, mode.count))
.collect::<Vec<_>>(),
correlation
.profile_span_counts
.iter()
.map(|entry| format!(
"0x{:x}:{}",
entry.previous_profile_chunk_len_to_next_name_or_end,
entry.count
))
.collect::<Vec<_>>(),
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no grounded 0xff0000ff/0x0002/0xff compact-prefix correlation was available".to_string()
}),
"cross-save q/p corpus checks now sharpen the mixed exact classes further without changing their identity: 0x000055f3/0x0001/0xff stays on prelude 0x0001/0xff with fixed short-flag pair 0x01/0x00 and fixed post-profile span 0x03 in both saves, while 0xff0000ff/0x0001/0xff stays on prelude 0x0001/0xff with fixed short-flag pair 0x00/0x00 and widely scattered post-profile spans in both saves".to_string(),
"that cross-save split keeps the semantic mix stable too: 0x000055f3/0x0001/0xff remains tunnel-dominant with only a small TrackCap residue, while 0xff0000ff/0x0001/0xff remains TrackCap-dominant with the same small tunnel-cap/section residue. So the next infrastructure question is no longer broad class identity; it is what the two short-flag families mean and why a minority of tunnel rows take the sparse 0xff0000ff outlier class instead of the stable span-0x03 tunnel family".to_string(),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary
.profile_span_correlations
.iter()
.find(|row| row.previous_profile_chunk_len_to_next_name_or_end == 0x27)
})
.map(|correlation| {
format!(
"the sparse 0x27 post-profile outlier is now explicit too: mode counts={:?}, prefix counts={:?}, sample rows={:?}",
correlation
.mode_family_counts
.iter()
.map(|mode| format!("{}:{}", mode.mode_family, mode.count))
.collect::<Vec<_>>(),
correlation
.compact_prefix_pattern_summaries
.iter()
.map(|prefix| format!(
"{}/{}/{}:{}",
prefix.prefix_leading_dword_hex,
prefix.prefix_trailing_word_hex,
prefix.prefix_separator_byte_hex,
prefix.count
))
.collect::<Vec<_>>(),
correlation
.sample_rows
.iter()
.map(|sample| format!(
"{}:{:?}/{:?}@{}/{}/{}",
sample.name_tag_relative_offset,
sample.primary_name,
sample.secondary_name,
sample.prefix_leading_dword_hex,
sample.prefix_trailing_word_hex,
sample.prefix_separator_byte_hex
))
.collect::<Vec<_>>()
)
})
.unwrap_or_else(|| {
"no grounded 0x27 post-profile outlier correlation was available for the prelude candidates".to_string()
}),
side_buffer
.and_then(|probe| probe.payload_envelope_summary.as_ref())
.and_then(|summary| summary.name_prelude_candidate_summary.as_ref())
.and_then(|summary| {
summary
.profile_span_correlations
.iter()
.find(|row| row.previous_profile_chunk_len_to_next_name_or_end == 0)
})
.map(|correlation| {
format!(
"the zero-length post-profile class is now a separate grounded outlier: dominant candidate pattern is {}/{} x{} across {} rows",
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.child_count_candidate_hex.as_str())
.unwrap_or("0x0000"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.saved_primary_child_byte_candidate_hex.as_str())
.unwrap_or("0x00"),
correlation
.dominant_candidate_pattern
.as_ref()
.map(|pattern| pattern.count)
.unwrap_or_default(),
correlation.row_count
)
})
.unwrap_or_else(|| {
"no grounded zero-length post-profile span correlation was available for the prelude candidates".to_string()
}),
"direct disassembly now also shows 0x530720 publishing the first fixed-triplet lane into [this+0x1e2/+0x1e6/+0x1ea], while 0x52e8b0 publishes the second fixed-triplet lane into [this+0x4b/+0x4f/+0x53] and sets bit 0x02".to_string(),
"direct disassembly now also shows the outer owner at 0x0048dcf0 reading one u16 child count through 0x531150 into the stream prelude, zeroing [this+0x08], and conditionally reading one saved primary-child byte before the per-child callback loop runs".to_string(),
side_buffer
.and_then(|probe| probe.live_entry_prelude_summary.as_ref())
.map(|summary| {
format!(
"the widened save-side probe now also decodes {} live-entry payload starts inside the records span; dominant child count={} x{}, dominant saved primary-child byte={} x{}, and {} payloads reach the first 0x55f1 child callback at offset +0x3",
summary.rows_with_payload_pointer_inside_records_span,
summary.dominant_child_count.unwrap_or_default(),
summary.dominant_child_count_count,
summary
.dominant_saved_primary_child_byte_hex
.as_deref()
.unwrap_or("0x00"),
summary.dominant_saved_primary_child_byte_count,
summary.rows_with_first_name_tag_at_offset_3
)
})
.unwrap_or_else(|| {
"no live-entry payload-start summary was available for the outer prelude".to_string()
}),
"local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x44 = 0x4559d0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string(),
"direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string(),
"direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string(),
"the smaller attach primitive 0x00490a3c no longer looks like the semantic fork by itself: it just allocates one literal Infrastructure child, seeds it through 0x455b70 with caller-provided stem input, attaches it through 0x5395d0, seeds position lanes through 0x539530/0x53a5b0, and optionally caches it as primary child".to_string(),
],
blockers: vec![
"how the remaining mixed exact compact-prefix classes map back onto constructor semantics now that the whole prelude corpus is split directly: 0xff0000ff/0x0002/0xff is pure bridge, 0xff000000/{0x0001,0x0002}/0xff are pure bridge, 0xf3010100/0x0055/0x00 is pure ballast-cap, and 0x0005d368/0x0001/0xff is pure track-cap, leaving only 0xff0000ff/0x0001/0xff and 0x000055f3/0x0001/0xff as the mixed residual classes".to_string(),
"how the payload streams reached through 0x00518380 -> 0x00518140 align with the embedded 0x55f1 name-pair groups and compact-prefix regimes surfaced by the save-side probe".to_string(),
"how the observed 0x55f3-to-next-0x55f1 gaps partition between the two 0x52ebd0 flag bytes and the next-record prelude now that 0x0048a6c0 is grounded as the writer for the outer child-count / primary-child prelude".to_string(),
"which fields written through the grounded 0x00490960 -> 0x004559d0 -> slot +0x4c -> 0x52ec50 chain retain the 0x38a5 embedded name-pair semantics before route/local-runtime follow-ons take over".to_string(),
],
},
SmpServiceConsumerHypothesis {
label: "infrastructure serializer/load companion path".to_string(),
status: if side_buffer.is_some() {
"strong_static_mapping_candidate".to_string()
} else {
"possible_consumer_family".to_string()
},
candidate_consumers: vec![
"0x004559d0 infrastructure tagged string-triplet serializer".to_string(),
"0x00455870 infrastructure tagged string-triplet load companion".to_string(),
"0x00455930 infrastructure scalar-triplet serializer sibling".to_string(),
],
evidence: vec![
"atlas already bounds the serializer/load strip around the Infrastructure owner and the same 0x55f1/0x55f2/0x55f3 tag family".to_string(),
"local .rdata at 0x005cfd00 now proves the infrastructure child vtable points straight at 0x455fc0/0x4559d0/0x455870/0x455930 for the load, tagged serializer, triplet-restore, and scalar serializer slots".to_string(),
"the save-side side-buffer carries embedded dual-name rows plus compact prefixes, which is compatible with a serializer-side bridge".to_string(),
],
blockers: vec![
"which exact 0x38a5 rows belong to shared 0x55f1/0x55f2/0x55f3 child records versus outer collection metadata, now that the concrete write-side slot +0x44 serializer is grounded as 0x004559d0".to_string(),
],
},
SmpServiceConsumerHypothesis {
label: "route/local-runtime follow-on path".to_string(),
status: if side_buffer.is_some() {
"secondary_candidate_after_attach_rebuild".to_string()
} else {
"possible_consumer_family".to_string()
},
candidate_consumers: vec![
"0x00448a70 / 0x00493660 / 0x0048b660 route and world follow-on family".to_string(),
"0x004133b0 placed-structure local-runtime refresh outer owner".to_string(),
],
evidence: vec![
"atlas ties the Infrastructure rebuild loop to later route-side and local-runtime follow-on owners".to_string(),
"current side-buffer trace shows separate infrastructure state and the direct seeded-lane bridge is now grounded before these later owners run".to_string(),
"direct disassembly now shows 0x00448a70 as a world-overlay byte write helper over [world+0x15e1/+0x162d], with the neighboring 0x00448af0 reading three world bitsets at [world+0x2139/+0x213d/+0x2141] rather than any infrastructure child fields".to_string(),
"direct disassembly now shows 0x00493660 as a counter-and-follow-on owner over one infrastructure child: it updates local counters by [child+0x218], [child+0x226], and [child+0x44], optionally resolves a peer through 0x48dcb0 and 0x426c20, then maps one world-raster byte back into the companion region collection 0x006cfc9c and calls 0x487960".to_string(),
"direct disassembly now shows 0x0048b660 as a presentation-color/style owner: it gates on global shell state, then branches on [child+0x216], [child+0x218], [child+0x226], [child+0x44], and bit 0x40 in [child+0x201] before publishing fixed RGBA tuples through 0x53a350".to_string(),
"the remaining local-runtime helpers are tighter now too: 0x0048e2c0 flips bit 0x20 in [child+0x201] and, when enabling that bit, reruns 0x53a3a0 plus 0x48a9e0; 0x0048e330 similarly flips bit 0x40 in [child+0x201] and tail-calls 0x48b660; and 0x0048e3c0 updates [child+0x22e] through the auxiliary route tracker 0x006cfcb4 after resolving one route entry via [child+0x212], then scans class-0 regions through 0x455800/0x455810 and 0x51dbb0 before setting bit 0x02 in [child+0x24c] only when the region test fails".to_string(),
],
blockers: vec![
"which mixed exact compact-prefix classes still survive into these later owners after the seeded-lane bridge and earlier child-stream restore semantics are accounted for".to_string(),
"no direct save-side correlation yet between the remaining mixed exact classes and the later 0x00493660 counter buckets, 0x0048b660 style branches, or the 0x0048e2c0/0x0048e3c0 flag-and-region follow-ons".to_string(),
],
},
];
let branches = vec![
build_service_trace_branch_status(
"infrastructure_asset_owner_seam",
if side_buffer.is_some() {
"grounded_separate_owner_seam"
} else {
"blocked_missing_side_buffer_owner_seam"
},
&[
"0x38a5/0x38a6/0x38a7 tagged family",
"embedded 0x55f1 dual-name rows",
"compact 6-byte prefix regimes",
],
if side_buffer.is_some() {
&[]
} else {
&["0x38a5 owner seam"]
},
&[
"0x00493be0 infrastructure tagged side-buffer collection load owner",
"0x0048dcf0 infrastructure tagged child-stream restore outer owner",
],
&[
"This seam should be treated as infrastructure-asset state rather than as a compact alias of placed-structure triplets.",
],
),
build_service_trace_branch_status(
"placed_structure_triplet_alias",
if alignment.is_some_and(|probe| probe.overlapping_name_pair_count == 0) {
"disproved_by_grounded_probe"
} else {
"unresolved"
},
&[
"0x36b1 placed-structure triplet corpus",
"0x38a5 side-buffer name-pair corpus",
],
&[],
&[],
&[
"Grounded q.gms evidence currently shows zero overlap between the side-buffer name-pair corpus and the placed-structure triplet name-pair corpus.",
],
),
build_service_trace_branch_status(
"city_connection_consumer_mapping",
"blocked_missing_infrastructure_asset_consumer_mapping",
&[
"grounded 0x38a5 owner seam",
"placed-structure triplet seam",
],
&[
"higher-layer consumer dispatch mapping",
"compact prefix regime semantics",
],
&[
"0x0048a1e0 infrastructure child attach helper",
"0x0048dd50 infrastructure child rebuild loop",
"0x00490a3c infrastructure payload attach helper",
],
&[
"The remaining problem is how higher-layer service code consumes this separate seam, not whether the seam exists.",
],
),
build_service_trace_branch_status(
"linked_transit_consumer_mapping",
"blocked_missing_infrastructure_asset_consumer_mapping",
&["grounded 0x38a5 owner seam", "company linked-transit latch"],
&[
"side-buffer consumer mapping",
"route or roster rebuild owner path",
],
&[
"0x00448a70 / 0x00493660 / 0x0048b660 route and world follow-on family",
"0x004133b0 placed-structure local-runtime refresh outer owner",
],
&[
"The next slice should target the consumer path above the side-buffer seam rather than another raw save scan.",
],
),
];
let notes = vec![
"Infrastructure asset trace now makes the side-buffer-versus-triplet split explicit: owner seam identity is grounded, the pure bridge-only 0x0002/0xff candidate class is grounded save-side, the upstream chooser above the child attach path is grounded as paired DT/ST siblings at 0x004a2c80 and 0x004a34e0 with decoded Bridge/Tunnel/BallastCap/Overpass families, grounded top-level branch meaning, grounded bridge/tunnel material selector roles, a concrete child-construction/write-side chain through 0x00490960, 0x00491c60, 0x0048a6c0, 0x00455a40, and 0x004559d0, and stable 0x00490960 mode families for BallastCap, TrackCap, Overpass, Tunnel, and Bridge branches. The current save-side name corpus already maps BallastCap, TrackCap, Tunnel, and Bridge rows onto those families directly, the candidate-pattern correlation narrows the dominant mixed 0x0001/0xff class to bridge:62 / track_cap:21 / tunnel:19, and the exact compact-prefix correlation now splits the full prelude corpus into mostly pure classes: 0xff0000ff/0x0002/0xff is pure bridge, 0xff000000/{0x0001,0x0002}/0xff are pure bridge, 0xf3010100/0x0055/0x00 is pure ballast-cap, and 0x0005d368/0x0001/0xff is pure track-cap, leaving only 0xff0000ff/0x0001/0xff and 0x000055f3/0x0001/0xff as the mixed residual classes.".to_string(),
"Cross-save q/p traces now also split those two mixed residual classes by footer and span behavior: 0x000055f3/0x0001/0xff always carries short-flag pair 0x01/0x00 on a fixed span-0x03 tunnel-dominant family, while 0xff0000ff/0x0001/0xff always carries short-flag pair 0x00/0x00 on the scattered-span TrackCap-dominant outlier family. The remaining unknown is therefore the meaning of those short-flag families and the sparse branch that routes a minority of tunnel rows into the 0xff0000ff outlier class.".to_string(),
"Direct consumers of those footer bits are grounded now too: bit 0x20 of [child+0x20] is the admission gate into the 0x00528d90 branch when no caller/global override is present, while bit 0x40 only feeds the later 0x00529730 -> 0x530280 follow-on. Since both mixed residual classes keep the second footer byte at zero in q/p, the remaining split is now specifically the first footer byte / bit-0x20 gate rather than both footer bytes.".to_string(),
"That bit-0x20 gate is no longer floating without context either: the 0x005295f0..0x005297b7 consumer strip repopulates candidate cells through 0x00533ba0, walks child lists through 0x00556ef0/0x00556f00, and honors the same controller mode byte [owner+0x3692] that the atlas already places under the world-window presentation dispatcher. The next infrastructure pass should therefore treat the remaining bit-0x20 question as a nearby-presentation/controller owner problem, not as a serializer-only problem.".to_string(),
"That owner family is layout-state specific now too: the surrounding helpers sit on atlas-backed layout/presenter roots, with 0x00548da0 walking layout list root [layout+0x2593] and 0x0054bab0 mutating layout slots [layout+0x2637/+0x263b/+0x2643]. So the remaining bit-0x20 split is increasingly a layout/presentation admission question above the infrastructure seam, not a simulation-owned route or rebuild question.".to_string(),
if st_only_name_pair_corpus {
"The current save-side side-buffer corpus is ST-only, so this trace directly exercises the ST chooser sibling while the DT sibling remains grounded statically but unexercised in this save.".to_string()
} else {
"The current save-side side-buffer corpus is not ST-only, so both chooser siblings or a DT-facing save-side class may be in play.".to_string()
},
];
SmpInfrastructureAssetTraceReport {
profile_family: analysis.profile_family.clone(),
placed_structure_collection_header_present: analysis
.placed_structure_collection_header
.is_some(),
placed_structure_record_triplet_count: analysis
.placed_structure_record_triplets
.as_ref()
.map(|probe| probe.record_count)
.unwrap_or_default(),
side_buffer_present: side_buffer.is_some(),
side_buffer_decoded_embedded_name_row_count: side_buffer
.map(|probe| probe.decoded_embedded_name_row_count)
.unwrap_or_default(),
side_buffer_unique_name_pair_count: side_buffer
.map(|probe| probe.unique_embedded_name_pair_count)
.unwrap_or_default(),
bridge_like_name_pair_count,
tunnel_like_name_pair_count,
track_cap_like_name_pair_count,
triplet_alignment_overlap_count: alignment
.map(|probe| probe.overlapping_name_pair_count)
.unwrap_or_default(),
atlas_candidate_consumers,
known_owner_bridge_fields,
known_bridge_helpers,
next_owner_questions,
candidate_consumer_hypotheses,
branches,
notes,
}
}
pub fn inspect_smp_bytes(bytes: &[u8]) -> SmpInspectionReport {
inspect_bundle_bytes(bytes, None)
}
pub fn load_save_slice_file(path: &Path) -> Result<SmpLoadedSaveSlice, Box<dyn std::error::Error>> {
let inspection = inspect_smp_file(path)?;
load_save_slice_from_report(&inspection)
.map_err(|err| -> Box<dyn std::error::Error> { err.into() })
}
pub fn load_save_slice_from_report(
report: &SmpInspectionReport,
) -> Result<SmpLoadedSaveSlice, String> {
let summary = report
.save_load_summary
.as_ref()
.ok_or_else(|| "inspection did not expose a recognizable save-load summary".to_string())?;
let profile = if let Some(probe) = &report.classic_rehydrate_profile_probe {
Some(SmpLoadedProfile {
profile_kind: "classic-rehydrate-profile".to_string(),
profile_family: probe.profile_family.clone(),
packed_profile_offset: probe.packed_profile_offset,
packed_profile_len: probe.packed_profile_len,
packed_profile_len_hex: probe.packed_profile_len_hex.clone(),
leading_word_0: probe.packed_profile_block.leading_word_0,
leading_word_0_hex: probe.packed_profile_block.leading_word_0_hex.clone(),
header_flag_word_3: None,
header_flag_word_3_hex: None,
map_path: probe.packed_profile_block.map_path.clone(),
display_name: probe.packed_profile_block.display_name.clone(),
profile_byte_0x77: probe.packed_profile_block.profile_byte_0x77,
profile_byte_0x77_hex: probe.packed_profile_block.profile_byte_0x77_hex.clone(),
profile_byte_0x82: probe.packed_profile_block.profile_byte_0x82,
profile_byte_0x82_hex: probe.packed_profile_block.profile_byte_0x82_hex.clone(),
profile_byte_0x97: probe.packed_profile_block.profile_byte_0x97,
profile_byte_0x97_hex: probe.packed_profile_block.profile_byte_0x97_hex.clone(),
profile_byte_0xc5: probe.packed_profile_block.profile_byte_0xc5,
profile_byte_0xc5_hex: probe.packed_profile_block.profile_byte_0xc5_hex.clone(),
})
} else {
report
.rt3_105_packed_profile_probe
.as_ref()
.map(|probe| SmpLoadedProfile {
profile_kind: "rt3-105-packed-profile".to_string(),
profile_family: probe.profile_family.clone(),
packed_profile_offset: probe.packed_profile_offset,
packed_profile_len: probe.packed_profile_len,
packed_profile_len_hex: probe.packed_profile_len_hex.clone(),
leading_word_0: probe.packed_profile_block.leading_word_0,
leading_word_0_hex: probe.packed_profile_block.leading_word_0_hex.clone(),
header_flag_word_3: Some(probe.packed_profile_block.header_flag_word_3),
header_flag_word_3_hex: Some(
probe.packed_profile_block.header_flag_word_3_hex.clone(),
),
map_path: probe.packed_profile_block.map_path.clone(),
display_name: probe.packed_profile_block.display_name.clone(),
profile_byte_0x77: probe.packed_profile_block.profile_byte_0x77,
profile_byte_0x77_hex: probe.packed_profile_block.profile_byte_0x77_hex.clone(),
profile_byte_0x82: probe.packed_profile_block.profile_byte_0x82,
profile_byte_0x82_hex: probe.packed_profile_block.profile_byte_0x82_hex.clone(),
profile_byte_0x97: probe.packed_profile_block.profile_byte_0x97,
profile_byte_0x97_hex: probe.packed_profile_block.profile_byte_0x97_hex.clone(),
profile_byte_0xc5: probe.packed_profile_block.profile_byte_0xc5,
profile_byte_0xc5_hex: probe.packed_profile_block.profile_byte_0xc5_hex.clone(),
})
};
let candidate_availability_table = report.rt3_105_save_name_table_probe.as_ref().map(|probe| {
SmpLoadedCandidateAvailabilityTable {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
header_offset: probe.header_offset,
entries_offset: probe.entries_offset,
entries_end_offset: probe.entries_end_offset,
observed_entry_count: probe.observed_entry_count,
zero_availability_count: probe.zero_trailer_entry_count,
zero_availability_names: probe.zero_trailer_entry_names.clone(),
footer_progress_hex_words: vec![
probe.footer_progress_word_0_hex.clone(),
probe.footer_progress_word_1_hex.clone(),
],
entries: probe.entries.clone(),
}
});
let named_locomotive_availability_table = report
.rt3_105_save_named_locomotive_availability_probe
.as_ref()
.map(|probe| SmpLoadedNamedLocomotiveAvailabilityTable {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
header_offset: None,
entries_offset: Some(probe.entries_offset),
entries_end_offset: Some(probe.entries_end_offset),
observed_entry_count: probe.observed_entry_count,
zero_availability_count: probe.zero_availability_count,
zero_availability_names: probe.zero_availability_names.clone(),
entries: probe.entries.clone(),
});
let locomotive_catalog = named_locomotive_availability_table
.as_ref()
.and_then(derive_locomotive_catalog_from_named_availability_table);
let cargo_catalog = report
.recipe_book_summary_probe
.as_ref()
.and_then(derive_cargo_catalog_from_recipe_book_probe);
let world_issue_37_state = report
.save_world_issue_37_probe
.as_ref()
.map(derive_loaded_world_issue_37_state_from_probe);
let world_economic_tuning_state = report
.save_world_economic_tuning_probe
.as_ref()
.map(derive_loaded_world_economic_tuning_state_from_probe);
let world_finance_neighborhood_state = report
.save_world_finance_neighborhood_probe
.as_ref()
.map(derive_loaded_world_finance_neighborhood_state_from_probe);
let world_locomotive_policy_state = derive_loaded_world_locomotive_policy_state_from_probes(
report.post_text_field_neighborhood_probe.as_ref(),
report.locomotive_policy_neighborhood_probe.as_ref(),
);
let company_roster = report.save_company_roster_probe.clone().or_else(|| {
report
.save_world_selection_context_probe
.as_ref()
.and_then(|probe| {
derive_selection_only_company_roster_from_save_world_probe(
probe,
report.save_company_collection_header_probe.as_ref(),
)
})
});
let chairman_profile_table = report
.save_chairman_profile_table_probe
.clone()
.or_else(|| {
report
.save_world_selection_context_probe
.as_ref()
.and_then(|probe| {
derive_selection_only_chairman_profile_table_from_save_world_probe(
probe,
report
.save_chairman_profile_collection_header_probe
.as_ref(),
)
})
});
let special_conditions_table =
report
.special_conditions_probe
.as_ref()
.map(|probe| SmpLoadedSpecialConditionsTable {
source_kind: probe.source_kind.clone(),
table_offset: probe.table_offset,
table_len: probe.table_len,
enabled_visible_count: probe.enabled_visible_count,
enabled_visible_labels: probe.enabled_visible_labels.clone(),
entries: probe.entries.clone(),
});
let placed_structure_dynamic_side_buffer_probe = report
.save_placed_structure_dynamic_side_buffer_probe
.clone();
let mut notes = summary.notes.clone();
if let Some(probe) = &report.save_world_selection_context_probe {
notes.push(format!(
"Raw save fixed world block exposes selected_company_id={} at file offset 0x{:x}.",
probe.selected_company_id, probe.selected_company_id_offset
));
notes.push(format!(
"Raw save fixed world block exposes selected_chairman_profile_id={} at file offset 0x{:x}.",
probe.selected_chairman_profile_id, probe.selected_chairman_profile_id_offset
));
notes.push(format!(
"Raw save fixed world block also exposes {} chairman slot selector bytes at file offset 0x{:x} and campaign_override_flag={} at file offset 0x{:x}.",
probe.chairman_slot_selectors.len(),
probe.chairman_slot_selector_offset,
probe.campaign_override_flag,
probe.campaign_override_flag_offset
));
if report.save_company_roster_probe.is_none()
|| report.save_chairman_profile_table_probe.is_none()
{
notes.push(
"Raw save inspection still does not reconstruct every company_roster or chairman_profile_table scalar lane; the grounded package-save path prefers direct-record reconstruction where it can and falls back to selection/header-only context otherwise."
.to_string(),
);
}
}
if let Some(probe) = &report.save_world_issue_37_probe {
notes.push(format!(
"Raw save fixed world block also exposes the grounded issue-0x37 pair: value={} at file offset 0x{:x} and companion multiplier {:.6} at file offset 0x{:x}.",
probe.issue_value_lane.value_i32,
probe.payload_offset + probe.issue_value_lane.relative_offset,
probe.multiplier_lane.value_f32,
probe.payload_offset + probe.multiplier_lane.relative_offset
));
}
if let Some(probe) = &report.save_world_economic_tuning_probe {
notes.push(format!(
"Raw save fixed world block also exposes the six-lane economic tuning float band at file offset 0x{:x} (mirror lane at 0x{:x}).",
probe.tuning_lanes
.first()
.map(|lane| probe.payload_offset + lane.relative_offset)
.unwrap_or(probe.payload_offset),
probe.payload_offset + probe.mirror_lane.relative_offset
));
notes.push(
"Current atlas evidence treats that fixed six-float world tuning band as the editor economic-cost family, not as the company-governance issue table behind investor confidence."
.to_string(),
);
}
if let Some(probe) = &report.save_company_collection_header_probe {
notes.push(format!(
"Raw save tagged company header reports live_record_count={} and live_id_bound={} at file offsets 0x{:x}/0x{:x}/0x{:x}.",
probe.live_record_count,
probe.live_id_bound,
probe.metadata_tag_offset,
probe.records_tag_offset,
probe.close_tag_offset
));
}
if let Some(probe) = &report.save_chairman_profile_collection_header_probe {
notes.push(format!(
"Raw save tagged chairman/profile header reports live_record_count={} and live_id_bound={} at file offsets 0x{:x}/0x{:x}/0x{:x}.",
probe.live_record_count,
probe.live_id_bound,
probe.metadata_tag_offset,
probe.records_tag_offset,
probe.close_tag_offset
));
}
if let Some(probe) = &report.save_train_collection_header_probe {
notes.push(format!(
"Raw save tagged train header reports live_record_count={} and live_id_bound={} with direct_record_stride=0x{:x} at file offsets 0x{:x}/0x{:x}/0x{:x}.",
probe.live_record_count,
probe.live_id_bound,
probe.direct_record_stride,
probe.metadata_tag_offset,
probe.records_tag_offset,
probe.close_tag_offset
));
}
if let Some(probe) = &report.save_train_collection_directory_probe {
notes.push(format!(
"Raw save tagged train metadata also exposes a live-entry directory with {} entries rooted at metadata dword {} (head={:?}, tail={:?}).",
probe.entries.len(),
probe.directory_root_dword_index,
probe.chain_head_live_entry_id,
probe.chain_tail_live_entry_id
));
}
if let Some(probe) = &report.save_region_collection_header_probe {
notes.push(format!(
"Raw save tagged region header reports live_record_count={} and live_id_bound={} with serialized stride hint 0x{:x} at file offsets 0x{:x}/0x{:x}/0x{:x}.",
probe.live_record_count,
probe.live_id_bound,
probe.direct_record_stride,
probe.metadata_tag_offset,
probe.records_tag_offset,
probe.close_tag_offset
));
}
if let Some(probe) = &report.save_region_record_triplet_probe {
notes.push(format!(
"Raw save tagged region records also expose {} repeated 0x55f1/0x55f2/0x55f3 triplets in the records span; first name={:?}, first policy lanes=({:.3}, {:.3}, {:.3}), trailing_word={}, first profile collection count={:?}, first profile collection trailing_padding_len={:?}.",
probe.record_count,
probe.entries.first().map(|entry| entry.name.as_str()),
probe.entries
.first()
.map(|entry| entry.policy_leading_f32_0)
.unwrap_or_default(),
probe.entries
.first()
.map(|entry| entry.policy_leading_f32_1)
.unwrap_or_default(),
probe.entries
.first()
.map(|entry| entry.policy_leading_f32_2)
.unwrap_or_default(),
probe.entries
.first()
.map(|entry| entry.policy_trailing_word_hex.as_str())
.unwrap_or("0x0000"),
probe.entries.first().and_then(|entry| {
entry.profile_collection.as_ref().map(|collection| collection.live_record_count)
}),
probe.entries.first().and_then(|entry| {
entry.profile_collection.as_ref().map(|collection| collection.trailing_padding_len)
})
));
}
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}.",
probe.live_record_count,
probe.live_id_bound,
probe.direct_record_stride,
probe.metadata_tag_offset,
probe.records_tag_offset,
probe.close_tag_offset
));
}
if let Some(probe) = &report.save_placed_structure_record_triplet_probe {
notes.push(format!(
"Raw save tagged placed-structure records also expose {} repeated 0x55f1/0x55f2/0x55f3 triplets; first stems={:?}/{:?}, first policy lanes=({:.3}, {:.3}, {:.3}, {:.3}, {:.3}), first footer payload={}, first footer status kind={:?}.",
probe.record_count,
probe.entries.first().map(|entry| entry.primary_name.as_str()),
probe.entries.first().map(|entry| entry.secondary_name.as_str()),
probe.entries.first().map(|entry| entry.policy_f32_lane_0).unwrap_or_default(),
probe.entries.first().map(|entry| entry.policy_f32_lane_1).unwrap_or_default(),
probe.entries.first().map(|entry| entry.policy_f32_lane_2).unwrap_or_default(),
probe.entries.first().map(|entry| entry.policy_f32_lane_3).unwrap_or_default(),
probe.entries.first().map(|entry| entry.policy_f32_lane_4).unwrap_or_default(),
probe.entries.first().map(|entry| entry.profile_payload_dword_hex.as_str()).unwrap_or("0x00000000"),
probe.entries.first().map(|entry| entry.profile_status_kind.as_str())
));
}
if let Some(probe) = &placed_structure_dynamic_side_buffer_probe {
let dominant_pattern = probe.compact_prefix_pattern_summaries.first();
let payload_envelope_summary = probe.payload_envelope_summary.as_ref();
let short_profile_flag_pair_summary = payload_envelope_summary
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref());
notes.push(format!(
"Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, owner-shared 0x38a6 dword={} at relative offset 0x{:x}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}/{:?}, embedded 0x55f1 row count={}, rows with tertiary 0x55f1 string={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, complete 0x55f1/0x55f2/0x55f3 envelopes={}, dominant 0x55f2 chunk len=0x{:x} x{}, dominant 0x55f3 span=0x{:x} x{}, dominant short 0x55f3 flag pair={}/{} x{}, dominant compact pattern={}/{}/{} x{}.",
probe.live_record_count,
probe.owner_shared_dword_hex,
probe.owner_shared_dword_relative_offset,
probe.prefix_leading_dword_hex,
probe.prefix_trailing_word_hex,
probe.prefix_separator_byte_hex,
probe.first_embedded_primary_name.as_deref(),
probe.first_embedded_secondary_name.as_deref(),
probe.first_embedded_tertiary_name.as_deref(),
probe.embedded_name_tag_count,
probe.decoded_embedded_name_row_with_tertiary_name_count,
probe.unique_compact_prefix_pattern_count,
probe.prefix_leading_dword_matching_embedded_profile_tag_count,
payload_envelope_summary
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
.unwrap_or_default(),
payload_envelope_summary
.and_then(|summary| summary.dominant_policy_chunk_len)
.unwrap_or_default(),
payload_envelope_summary
.map(|summary| summary.dominant_policy_chunk_len_count)
.unwrap_or_default(),
payload_envelope_summary
.and_then(|summary| summary.dominant_profile_chunk_len)
.unwrap_or_default(),
payload_envelope_summary
.map(|summary| summary.dominant_profile_chunk_len_count)
.unwrap_or_default(),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.first_flag_byte_hex.as_str())
.unwrap_or("0x00"),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.second_flag_byte_hex.as_str())
.unwrap_or("0x00"),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.count)
.unwrap_or_default(),
dominant_pattern
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
.unwrap_or("0x00000000"),
dominant_pattern
.map(|pattern| pattern.prefix_trailing_word_hex.as_str())
.unwrap_or("0x0000"),
dominant_pattern
.map(|pattern| pattern.prefix_separator_byte_hex.as_str())
.unwrap_or("0x00"),
dominant_pattern.map(|pattern| pattern.count).unwrap_or_default()
));
if probe.owner_shared_dword_matches_first_compact_prefix_leading_dword {
notes.push(
"Direct disassembly now shows 0x00493be0 consuming one shared 0x38a6 owner-local dword before iterating records; the first compact-prefix leading dword currently reuses that same lane."
.to_string(),
);
}
}
if let Some(roster) = &report.save_company_roster_probe {
notes.push(format!(
"Raw save inspection reconstructed {} company direct records from the tagged company collection.",
roster.entries.len()
));
}
if let Some(table) = &report.save_chairman_profile_table_probe {
notes.push(format!(
"Raw save inspection reconstructed {} chairman/profile direct records from the tagged chairman collection.",
table.entries.len()
));
}
Ok(SmpLoadedSaveSlice {
file_extension_hint: summary.file_extension_hint.clone(),
container_profile_family: summary.container_profile_family.clone(),
mechanism_family: summary.mechanism_family.clone(),
mechanism_confidence: summary.mechanism_confidence.clone(),
trailer_family: summary.trailer_family.clone(),
bridge_family: summary.bridge_family.clone(),
profile,
candidate_availability_table,
named_locomotive_availability_table,
locomotive_catalog,
cargo_catalog,
world_issue_37_state,
world_economic_tuning_state,
world_finance_neighborhood_state,
world_locomotive_policy_state,
company_roster,
chairman_profile_table,
special_conditions_table,
event_runtime_collection: report.event_runtime_collection_summary.clone(),
notes,
})
}
pub fn inspect_save_company_and_chairman_analysis_file(
path: &Path,
) -> Result<SmpSaveCompanyChairmanAnalysisReport, Box<dyn std::error::Error>> {
let bytes = fs::read(path)?;
let report = inspect_bundle_bytes(
&bytes,
path.extension()
.and_then(|extension| extension.to_str())
.map(|extension| extension.to_ascii_lowercase()),
);
inspect_save_company_and_chairman_analysis_bytes(&bytes, &report)
.ok_or_else(|| "save inspection did not expose grounded company/chairman analysis".into())
}
pub fn inspect_save_company_and_chairman_analysis_bytes(
bytes: &[u8],
report: &SmpInspectionReport,
) -> Option<SmpSaveCompanyChairmanAnalysisReport> {
let selection_probe = report.save_world_selection_context_probe.as_ref();
let world_selection_context = selection_probe.map(build_save_world_selection_role_analysis);
let world_issue_37 = report.save_world_issue_37_probe.clone();
let world_economic_tuning = report.save_world_economic_tuning_probe.clone();
let world_finance_neighborhood = report.save_world_finance_neighborhood_probe.clone();
let train_collection_directory = report.save_train_collection_directory_probe.clone();
let region_record_triplets = report.save_region_record_triplet_probe.clone();
let region_queued_notice_records = report
.save_region_queued_notice_record_probe
.clone()
.or_else(|| {
parse_save_region_queued_notice_record_probe(
bytes,
report.file_extension_hint.as_deref(),
report.container_profile.as_ref(),
report.save_region_collection_header_probe.as_ref(),
)
});
let region_fixed_row_run_candidates = report
.save_region_fixed_row_run_candidate_probe
.clone()
.or_else(|| {
parse_save_region_fixed_row_run_candidate_probe(
bytes,
report.file_extension_hint.as_deref(),
report.container_profile.as_ref(),
report.save_region_collection_header_probe.as_ref(),
)
});
let placed_structure_record_triplets =
report.save_placed_structure_record_triplet_probe.clone();
let placed_structure_dynamic_side_buffer = report
.save_placed_structure_dynamic_side_buffer_probe
.clone()
.or_else(|| {
parse_save_placed_structure_dynamic_side_buffer_probe(
bytes,
report.file_extension_hint.as_deref(),
report.container_profile.as_ref(),
)
});
let placed_structure_dynamic_side_buffer_alignment = placed_structure_dynamic_side_buffer
.as_ref()
.zip(placed_structure_record_triplets.as_ref())
.map(|(side_buffer, triplets)| {
summarize_placed_structure_dynamic_side_buffer_alignment(side_buffer, triplets)
});
let unclassified_tagged_collection_headers = report
.save_unclassified_tagged_collection_header_probes
.clone();
let company_header_probe = report.save_company_collection_header_probe.as_ref();
let chairman_header_probe = report
.save_chairman_profile_collection_header_probe
.as_ref();
let company_entries = if let Some(header_probe) = company_header_probe {
let record_start_offset = detect_save_company_record_start_offset(&bytes, header_probe)?;
let record_stride = header_probe.direct_record_stride as usize;
let base_offset = header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(record_start_offset)?;
let mut entries = Vec::with_capacity(header_probe.live_record_count as usize);
for index in 0..header_probe.live_record_count as usize {
let record_offset = base_offset.checked_add(index.checked_mul(record_stride)?)?;
let company_id = read_u32_at(&bytes, record_offset)?;
let name = read_ascii_c_string_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_NAME_OFFSET,
SAVE_COMPANY_RECORD_NAME_MAX_LEN,
)?;
let active =
read_u8_at(&bytes, record_offset + SAVE_COMPANY_RECORD_ACTIVE_OFFSET)? != 0;
let linked_chairman_profile_id = parse_nonzero_u32(
&bytes,
record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET,
)?;
let outstanding_shares = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_OUTSTANDING_SHARES_OFFSET,
)?;
let debt = parse_save_company_total_debt(&bytes, record_offset)?;
let bond_count = read_u8_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET,
)?;
let live_bond_slots = parse_save_company_live_bond_slots(&bytes, record_offset)?;
let largest_live_bond_principal =
parse_save_company_largest_live_bond_principal(&bytes, record_offset)?;
let highest_coupon_live_bond_principal =
parse_save_company_highest_coupon_live_bond_principal(&bytes, record_offset)?;
let available_track_laying_capacity =
parse_save_company_available_track_laying_capacity(&bytes, record_offset)?;
let company_value_scalar_f32 = read_f32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET,
)?;
let cached_share_support_scalar_f32 = read_f32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET,
)?;
let cached_share_price_f32 = read_f32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET,
)?;
let chairman_salary_baseline = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET,
)?;
let chairman_salary_current = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET,
)?;
let chairman_bonus_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_YEAR_OFFSET,
)?;
let chairman_bonus_amount = read_i32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_AMOUNT_OFFSET,
)?;
let founding_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET,
)?;
let last_bankruptcy_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET,
)?;
let last_dividend_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET,
)?;
let preferred_locomotive_engine_type_raw_u8 = read_u8_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_PREFERRED_LOCOMOTIVE_ENGINE_TYPE_OFFSET,
)?;
let city_connection_latch = read_u8_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET,
)? != 0;
let linked_transit_latch = read_u8_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET,
)? != 0;
let merger_cooldown_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET,
)?;
let takeover_cooldown_year = read_u32_at(
&bytes,
record_offset + SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET,
)?;
let scalar_dword_candidates = SAVE_COMPANY_RECORD_SCALAR_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(&bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let post_capacity_dword_candidates = SAVE_COMPANY_RECORD_POST_CAPACITY_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(&bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_0cfb_candidates = build_save_company_stat_band_candidates(
&bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET,
"stat_band_0cfb",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
let stat_band_root_0d7f_candidates = build_save_company_stat_band_candidates(
&bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET,
"stat_band_0d7f",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
let stat_band_root_1c47_candidates = build_save_company_stat_band_candidates(
&bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET,
"stat_band_1c47",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
entries.push(SmpSaveCompanyRecordAnalysisEntry {
company_id,
name,
active,
linked_chairman_profile_id,
outstanding_shares,
debt,
bond_count,
live_bond_slots,
largest_live_bond_principal,
highest_coupon_live_bond_principal,
available_track_laying_capacity,
company_value_scalar_f32,
cached_share_support_scalar_f32,
cached_share_price_f32,
chairman_salary_baseline,
chairman_salary_current,
chairman_bonus_year,
chairman_bonus_amount,
founding_year,
last_bankruptcy_year,
last_dividend_year,
preferred_locomotive_engine_type_raw_u8,
preferred_locomotive_engine_type_raw_hex: format!(
"0x{preferred_locomotive_engine_type_raw_u8:02x}"
),
city_connection_latch,
linked_transit_latch,
merger_cooldown_year,
takeover_cooldown_year,
scalar_dword_candidates,
post_capacity_dword_candidates,
stat_band_root_0cfb_candidates,
stat_band_root_0d7f_candidates,
stat_band_root_1c47_candidates,
});
}
entries
} else {
Vec::new()
};
let company_share_prices = company_entries
.iter()
.filter_map(|entry| {
round_f64_to_i64(entry.cached_share_price_f32 as f64)
.map(|share_price| (entry.company_id, share_price))
})
.collect::<BTreeMap<_, _>>();
let chairman_entries = if let Some(header_probe) = chairman_header_probe {
let record_start_offset =
detect_save_chairman_profile_record_start_offset(&bytes, header_probe)?;
let record_stride = header_probe.direct_record_stride as usize;
let base_offset = header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(record_start_offset)?;
let company_id_bound = company_header_probe
.map(|probe| probe.live_id_bound)
.unwrap_or(0);
let mut entries = Vec::with_capacity(header_probe.live_record_count as usize);
for index in 0..header_probe.live_record_count as usize {
let record_offset = base_offset.checked_add(index.checked_mul(record_stride)?)?;
let profile_id = read_u32_at(&bytes, record_offset)?;
let active = read_u32_at(&bytes, record_offset + 4)? != 0;
let name = read_ascii_c_string_at(
&bytes,
record_offset + SAVE_CHAIRMAN_RECORD_NAME_OFFSET,
SAVE_CHAIRMAN_RECORD_NAME_MAX_LEN,
)?;
let current_cash =
read_f64_at(&bytes, record_offset + SAVE_CHAIRMAN_RECORD_CASH_OFFSET)?;
let linked_company_id = parse_nonzero_u32(
&bytes,
record_offset + SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET,
)?;
let personality_byte_0x291 = read_u8_at(
&bytes,
record_offset + SAVE_CHAIRMAN_RECORD_PERSONALITY_BYTE_0X291_OFFSET,
)?;
let mut holdings_by_company = BTreeMap::new();
for company_id in 1..=company_id_bound {
let slot_offset = record_offset
.checked_add(SAVE_CHAIRMAN_RECORD_HOLDINGS_BASE_OFFSET)?
.checked_add((company_id as usize).checked_mul(4)?)?;
let units = read_u32_at(&bytes, slot_offset)?;
if units != 0 {
holdings_by_company.insert(company_id, units);
}
}
let cached_scalar_candidates = SAVE_CHAIRMAN_RECORD_CACHE_CANDIDATE_OFFSETS
.iter()
.map(|relative_offset| {
build_save_qword_candidate(&bytes, record_offset, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let rounded_current_cash = round_f64_to_i64(current_cash)?;
let derived_holdings_share_price_total = derive_chairman_holdings_share_price_total(
&holdings_by_company,
&company_share_prices,
);
let derived_net_worth_share_price_total = derived_holdings_share_price_total
.and_then(|holdings_total| rounded_current_cash.checked_add(holdings_total));
let derived_cached_purchasing_power_total =
derive_chairman_cached_purchasing_power_total(
rounded_current_cash,
&cached_scalar_candidates,
);
entries.push(SmpSaveChairmanRecordAnalysisEntry {
profile_id,
name,
active,
current_cash,
linked_company_id,
holdings_by_company,
derived_holdings_share_price_total,
derived_net_worth_share_price_total,
derived_cached_purchasing_power_total,
personality_byte_0x291,
personality_byte_0x291_hex: format!("0x{personality_byte_0x291:02x}"),
cached_scalar_candidates,
});
}
entries
} else {
Vec::new()
};
let mut notes = Vec::new();
if world_selection_context.is_some() {
notes.push(
"World selection context now exports the grounded chairman-slot selector bytes and per-slot role-gate bytes from the fixed save-side 0x32c8 world block."
.to_string(),
);
}
if world_issue_37.is_some() {
notes.push(
"World analysis now also exports the grounded issue-0x37 pair from the same 0x32c8 world payload: the clamped small issue value at [world+0x2d] and its companion multiplier lane at [world+0x29]."
.to_string(),
);
}
if world_economic_tuning.is_some() {
notes.push(
"World analysis now also exports the fixed six-lane economic tuning float block from the same 0x32c8 world payload; current atlas evidence still treats that band as distinct from the issue-0x37 investor-confidence family."
.to_string(),
);
}
if world_finance_neighborhood.is_some() {
notes.push(
"World analysis now also exports one fixed dword finance neighborhood around the grounded issue/calendar lanes, so future issue-0x38/0x39 closure can build on rehosted owner-state candidates instead of ad hoc byte guesses."
.to_string(),
);
}
if let Some(header) = report.save_train_collection_header_probe.as_ref() {
notes.push(format!(
"Train analysis now also exports the tagged train collection header: live_record_count={} live_id_bound={} direct_record_stride=0x{:x}.",
header.live_record_count, header.live_id_bound, header.direct_record_stride
));
}
if let Some(directory) = train_collection_directory.as_ref() {
notes.push(format!(
"Train analysis now also exports the tagged live-entry directory rooted at metadata dword {}: {} entries chained from {:?} to {:?}.",
directory.directory_root_dword_index,
directory.entries.len(),
directory.chain_head_live_entry_id,
directory.chain_tail_live_entry_id
));
}
if let Some(header) = report.save_region_collection_header_probe.as_ref() {
notes.push(format!(
"Region analysis now also exports the non-direct tagged region collection header: live_record_count={} live_id_bound={} serialized_stride_hint=0x{:x}.",
header.live_record_count, header.live_id_bound, header.direct_record_stride
));
}
if let Some(triplets) = region_record_triplets.as_ref() {
notes.push(format!(
"Region analysis now also exports {} tagged 0x55f1/0x55f2/0x55f3 record triplets; first serialized region name={:?}, first policy lanes=({:.3}, {:.3}, {:.3}), first profile collection count={:?}, first profile collection trailing_padding_len={:?}.",
triplets.record_count,
triplets.entries.first().map(|entry| entry.name.as_str()),
triplets
.entries
.first()
.map(|entry| entry.policy_leading_f32_0)
.unwrap_or_default(),
triplets
.entries
.first()
.map(|entry| entry.policy_leading_f32_1)
.unwrap_or_default(),
triplets
.entries
.first()
.map(|entry| entry.policy_leading_f32_2)
.unwrap_or_default(),
triplets.entries.first().and_then(|entry| {
entry.profile_collection.as_ref().map(|collection| collection.live_record_count)
}),
triplets.entries.first().and_then(|entry| {
entry.profile_collection.as_ref().map(|collection| collection.trailing_padding_len)
})
));
}
if let Some(queue_probe) = region_queued_notice_records.as_ref() {
notes.push(format!(
"Region analysis now also exports {} queued kind-7 notice nodes with payload seed {}: first region id={} amount={} promotion={} tails={}/{}.",
queue_probe.entries.len(),
queue_probe.payload_seed_dword_hex,
queue_probe.entries[0].region_id,
queue_probe.entries[0].amount,
queue_probe.entries[0].promotion_latch_dword_hex,
queue_probe.entries[0].trailing_sentinel_i32_0_hex,
queue_probe.entries[0].trailing_sentinel_i32_1_hex
));
}
if let Some(fixed_row_candidates) = region_fixed_row_run_candidates.as_ref() {
notes.push(format!(
"Region analysis now also exports {} fixed-row run candidates keyed to live_record_count={} and stride {} before the tagged region metadata; best candidate rows offset is {:?} with shape signature {:?}.",
fixed_row_candidates.candidates.len(),
fixed_row_candidates.target_row_count,
fixed_row_candidates.target_row_stride_hex,
fixed_row_candidates
.candidates
.first()
.map(|candidate| candidate.rows_offset_hex.as_str()),
fixed_row_candidates
.candidates
.first()
.map(|candidate| candidate.shape_signature.as_str())
));
}
if let Some(header) = report
.save_placed_structure_collection_header_probe
.as_ref()
{
notes.push(format!(
"Placed-structure analysis now also exports the tagged collection header: live_record_count={} live_id_bound={} serialized_stride_hint=0x{:x}.",
header.live_record_count, header.live_id_bound, header.direct_record_stride
));
}
if let Some(triplets) = placed_structure_record_triplets.as_ref() {
notes.push(format!(
"Placed-structure analysis now also exports {} tagged 0x55f1/0x55f2/0x55f3 record triplets; first stems={:?}/{:?}, first footer payload={}, first footer status kind={:?}.",
triplets.record_count,
triplets.entries.first().map(|entry| entry.primary_name.as_str()),
triplets.entries.first().map(|entry| entry.secondary_name.as_str()),
triplets.entries.first().map(|entry| entry.profile_payload_dword_hex.as_str()).unwrap_or("0x00000000"),
triplets.entries.first().map(|entry| entry.profile_status_kind.as_str())
));
}
if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() {
let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first();
let payload_envelope_summary = side_buffer.payload_envelope_summary.as_ref();
let short_profile_flag_pair_summary = payload_envelope_summary
.and_then(|summary| summary.short_profile_flag_pair_summary.as_ref());
notes.push(format!(
"Placed-structure analysis now also exports the separate 0x38a5 dynamic side-buffer owner seam with {} embedded name rows, {} decoded rows across {} unique name pairs, {} rows with a tertiary 0x55f1 string, {} unique compact prefix patterns, {} rows whose leading dword matches 0x55f3, {} complete 0x55f1/0x55f2/0x55f3 envelopes, dominant 0x55f2 chunk len=0x{:x} x{}, dominant 0x55f3 span=0x{:x} x{}, dominant short 0x55f3 flag pair={}/{} x{}, and dominant compact pattern={}/{}/{} x{}.",
side_buffer.embedded_name_tag_count,
side_buffer.decoded_embedded_name_row_count,
side_buffer.unique_embedded_name_pair_count,
side_buffer.decoded_embedded_name_row_with_tertiary_name_count,
side_buffer.unique_compact_prefix_pattern_count,
side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count,
payload_envelope_summary
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
.unwrap_or_default(),
payload_envelope_summary
.and_then(|summary| summary.dominant_policy_chunk_len)
.unwrap_or_default(),
payload_envelope_summary
.map(|summary| summary.dominant_policy_chunk_len_count)
.unwrap_or_default(),
payload_envelope_summary
.and_then(|summary| summary.dominant_profile_chunk_len)
.unwrap_or_default(),
payload_envelope_summary
.map(|summary| summary.dominant_profile_chunk_len_count)
.unwrap_or_default(),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.first_flag_byte_hex.as_str())
.unwrap_or("0x00"),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.second_flag_byte_hex.as_str())
.unwrap_or("0x00"),
short_profile_flag_pair_summary
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| pair.count)
.unwrap_or_default(),
dominant_pattern
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
.unwrap_or("0x00000000"),
dominant_pattern
.map(|pattern| pattern.prefix_trailing_word_hex.as_str())
.unwrap_or("0x0000"),
dominant_pattern
.map(|pattern| pattern.prefix_separator_byte_hex.as_str())
.unwrap_or("0x00"),
dominant_pattern.map(|pattern| pattern.count).unwrap_or_default()
));
}
if let Some(alignment) = placed_structure_dynamic_side_buffer_alignment.as_ref() {
notes.push(format!(
"Placed-structure analysis now also compares the 0x38a5 side-buffer against the grounded 0x36b1 triplet corpus: {} of {} decoded side-buffer rows reuse {} overlapping placed-structure name pairs, leaving {} unmatched side-buffer rows and {} triplet-only name pairs.",
alignment.side_buffer_rows_with_matching_triplet_name_pair_count,
alignment.side_buffer_row_count,
alignment.overlapping_name_pair_count,
alignment.side_buffer_rows_without_matching_triplet_name_pair_count,
alignment.triplet_name_pairs_without_side_buffer_match_count
));
}
if let Some(candidate) = unclassified_tagged_collection_headers.first() {
notes.push(format!(
"Generic save-side tagged collection scan also found {} unclassified candidate families; largest current candidate uses tags {}/{}/{} with live_record_count={} stride=0x{:x} records_span_len=0x{:x}.",
unclassified_tagged_collection_headers.len(),
candidate.metadata_tag_hex,
candidate.records_tag_hex,
candidate.close_tag_hex,
candidate.live_record_count,
candidate.direct_record_stride,
candidate.records_span_len
));
}
if !company_entries.is_empty() {
notes.push(
"Company debt is derived from the grounded bond table at [company+0x5b/+0x5f] by summing live principal slots.".to_string(),
);
notes.push(
"Company available_track_laying_capacity is derived from the grounded tail dword [company+0x7680], with negative values treated as the unlimited sentinel.".to_string(),
);
notes.push(
"Company scalar_dword_candidates expose the current checked-in raw save windows around support/share-price/calendar lanes, and post_capacity_dword_candidates expose the immediate dwords after [company+0x7680] for deeper track-count and record-tail analysis.".to_string(),
);
notes.push(
"Company stat-band root candidates now also expose the first dword windows rooted at [company+0x0cfb], [company+0x0d7f], and [company+0x1c47], the same broader stat bands the grounded cheat reset branch clears before later finance/detail readers rebuild them.".to_string(),
);
notes.push(
"Current atlas evidence ties company current_cash and book_value_per_share to stat-family 0x2329 slots 0x0d and 0x1d, so the remaining save-native company finance/governance closure likely needs a structured company-stat family reconstruction instead of more isolated raw offsets."
.to_string(),
);
}
if !chairman_entries.is_empty() {
notes.push(
"Chairman cached_scalar_candidates expose the adjacent qword band rooted at [profile+0x1e9], now including raw qword hex and signed/f64 views for further purchasing-power analysis.".to_string(),
);
notes.push(
"Chairman analysis now also derives one holdings-at-cached-share-price total from the grounded company cached_share_price lane and one strongest-cached purchasing-power total from the nonnegative qword cache band."
.to_string(),
);
}
Some(SmpSaveCompanyChairmanAnalysisReport {
profile_family: report
.container_profile
.as_ref()
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string()),
selected_company_id: selection_probe.map(|probe| probe.selected_company_id),
selected_chairman_profile_id: selection_probe
.map(|probe| probe.selected_chairman_profile_id),
world_selection_context,
world_issue_37,
world_economic_tuning,
world_finance_neighborhood,
train_collection_header: report.save_train_collection_header_probe.clone(),
train_collection_directory,
region_collection_header: report.save_region_collection_header_probe.clone(),
region_record_triplets,
region_queued_notice_records,
region_fixed_row_run_candidates,
placed_structure_collection_header: report
.save_placed_structure_collection_header_probe
.clone(),
placed_structure_record_triplets,
placed_structure_dynamic_side_buffer,
placed_structure_dynamic_side_buffer_alignment,
unclassified_tagged_collection_headers,
company_entries,
chairman_entries,
notes,
})
}
pub fn compare_save_region_fixed_row_run_candidates(
left: &SmpSaveCompanyChairmanAnalysisReport,
right: &SmpSaveCompanyChairmanAnalysisReport,
) -> Option<SmpSaveRegionFixedRowRunComparisonReport> {
let left_probe = left.region_fixed_row_run_candidates.as_ref()?;
let right_probe = right.region_fixed_row_run_candidates.as_ref()?;
let left_by_shape = left_probe
.candidates
.iter()
.enumerate()
.map(|(index, candidate)| (candidate.shape_signature.clone(), (index, candidate)))
.collect::<BTreeMap<_, _>>();
let right_by_shape = right_probe
.candidates
.iter()
.enumerate()
.map(|(index, candidate)| (candidate.shape_signature.clone(), (index, candidate)))
.collect::<BTreeMap<_, _>>();
let mut shared_shape_matches = Vec::new();
let mut shared_shape_family_matches = Vec::new();
let mut left_only_shape_signatures = Vec::new();
let mut right_only_shape_signatures = Vec::new();
let mut left_only_shape_family_signatures = Vec::new();
let mut right_only_shape_family_signatures = Vec::new();
let left_family_by_shape = left_probe
.candidates
.iter()
.enumerate()
.map(|(index, candidate)| (candidate.shape_family_signature.clone(), (index, candidate)))
.collect::<BTreeMap<_, _>>();
let right_family_by_shape = right_probe
.candidates
.iter()
.enumerate()
.map(|(index, candidate)| (candidate.shape_family_signature.clone(), (index, candidate)))
.collect::<BTreeMap<_, _>>();
for (shape_signature, (left_index, left_candidate)) in &left_by_shape {
if let Some((right_index, right_candidate)) = right_by_shape.get(shape_signature) {
shared_shape_matches.push(SmpSaveRegionFixedRowRunSharedShapeMatch {
shape_signature: shape_signature.clone(),
left_rank: left_index + 1,
left_rows_offset_hex: left_candidate.rows_offset_hex.clone(),
left_best_probable_density_lane_relative_offset_hex: left_candidate
.best_probable_density_lane_relative_offset_hex
.clone(),
right_rank: right_index + 1,
right_rows_offset_hex: right_candidate.rows_offset_hex.clone(),
right_best_probable_density_lane_relative_offset_hex: right_candidate
.best_probable_density_lane_relative_offset_hex
.clone(),
});
} else {
left_only_shape_signatures.push(shape_signature.clone());
}
}
for shape_signature in right_by_shape.keys() {
if !left_by_shape.contains_key(shape_signature) {
right_only_shape_signatures.push(shape_signature.clone());
}
}
for (shape_family_signature, (left_index, left_candidate)) in &left_family_by_shape {
if let Some((right_index, right_candidate)) =
right_family_by_shape.get(shape_family_signature)
{
shared_shape_family_matches.push(SmpSaveRegionFixedRowRunSharedShapeMatch {
shape_signature: shape_family_signature.clone(),
left_rank: left_index + 1,
left_rows_offset_hex: left_candidate.rows_offset_hex.clone(),
left_best_probable_density_lane_relative_offset_hex: left_candidate
.best_probable_density_lane_relative_offset_hex
.clone(),
right_rank: right_index + 1,
right_rows_offset_hex: right_candidate.rows_offset_hex.clone(),
right_best_probable_density_lane_relative_offset_hex: right_candidate
.best_probable_density_lane_relative_offset_hex
.clone(),
});
} else {
left_only_shape_family_signatures.push(shape_family_signature.clone());
}
}
for shape_family_signature in right_family_by_shape.keys() {
if !left_family_by_shape.contains_key(shape_family_signature) {
right_only_shape_family_signatures.push(shape_family_signature.clone());
}
}
Some(SmpSaveRegionFixedRowRunComparisonReport {
left_profile_family: left.profile_family.clone(),
right_profile_family: right.profile_family.clone(),
left_best_rows_offset_hex: left_probe
.candidates
.first()
.map(|candidate| candidate.rows_offset_hex.clone()),
right_best_rows_offset_hex: right_probe
.candidates
.first()
.map(|candidate| candidate.rows_offset_hex.clone()),
left_best_shape_signature: left_probe
.candidates
.first()
.map(|candidate| candidate.shape_signature.clone()),
right_best_shape_signature: right_probe
.candidates
.first()
.map(|candidate| candidate.shape_signature.clone()),
left_best_shape_family_signature: left_probe
.candidates
.first()
.map(|candidate| candidate.shape_family_signature.clone()),
right_best_shape_family_signature: right_probe
.candidates
.first()
.map(|candidate| candidate.shape_family_signature.clone()),
shared_shape_matches,
shared_shape_family_matches,
left_only_shape_signatures,
right_only_shape_signatures,
left_only_shape_family_signatures,
right_only_shape_family_signatures,
evidence: vec![
format!(
"comparison keys the pre-region-header fixed-row candidates by derived lane-shape fingerprint instead of raw offset, because current grounded saves do not keep the same top rows_offset across files ({:?} vs {:?})",
left_probe.candidates.first().map(|candidate| candidate.rows_offset_hex.as_str()),
right_probe.candidates.first().map(|candidate| candidate.rows_offset_hex.as_str())
),
"shared shape matches mean two saves surfaced at least one candidate with the same exact probable-f32/small-unsigned/partial-zero/trailing-byte profile, while shared shape-family matches allow mild count drift inside the same dense lane family".to_string(),
],
})
}
fn derive_locomotive_catalog_from_named_availability_table(
table: &SmpLoadedNamedLocomotiveAvailabilityTable,
) -> Option<SmpLoadedLocomotiveCatalog> {
if table.entries.is_empty() {
return None;
}
let entries = table
.entries
.iter()
.enumerate()
.map(|(index, entry)| SmpLoadedLocomotiveCatalogEntry {
locomotive_id: (index + 1) as u32,
name: entry.text.clone(),
})
.collect::<Vec<_>>();
Some(SmpLoadedLocomotiveCatalog {
source_kind: format!("{}-ordinal-catalog", table.source_kind),
semantic_family: "scenario-save-derived-locomotive-catalog".to_string(),
entries_offset: table.entries_offset,
observed_entry_count: entries.len(),
entries,
})
}
fn derive_cargo_catalog_from_recipe_book_probe(
probe: &SmpRecipeBookSummaryProbe,
) -> Option<SmpLoadedCargoCatalog> {
if probe.books.is_empty() {
return None;
}
let entries = probe
.books
.iter()
.filter(|book| book.book_index < 11)
.filter_map(|book| {
let line = book
.lines
.iter()
.find(|line| line.imports_to_runtime_descriptor)
.or_else(|| book.lines.first())?;
let slot_id = (book.book_index + 1) as u32;
let definition = known_cargo_slot_definition(slot_id)?;
Some(SmpLoadedCargoCatalogEntry {
slot_id,
label: definition.label.to_string(),
cargo_class: definition.cargo_class,
book_index: book.book_index,
max_annual_production_word: book.max_annual_production_word,
mode_word: line.mode_word,
runtime_import_branch_kind: line.runtime_import_branch_kind.clone(),
annual_amount_word: line.annual_amount_word,
supplied_cargo_token_word: line.supplied_cargo_token_word,
supplied_cargo_token_probable_high16_ascii_stem: line
.supplied_cargo_token_probable_high16_ascii_stem
.clone(),
demanded_cargo_token_word: line.demanded_cargo_token_word,
demanded_cargo_token_probable_high16_ascii_stem: line
.demanded_cargo_token_probable_high16_ascii_stem
.clone(),
})
})
.collect::<Vec<_>>();
if entries.is_empty() {
return None;
}
Some(SmpLoadedCargoCatalog {
source_kind: format!("{}-slot-catalog", probe.source_kind),
semantic_family: "scenario-save-derived-cargo-catalog".to_string(),
root_offset: Some(probe.root_offset),
observed_entry_count: entries.len(),
entries,
})
}
fn derive_loaded_world_issue_37_state_from_probe(
probe: &SmpSaveWorldIssue37Probe,
) -> SmpLoadedWorldIssue37State {
SmpLoadedWorldIssue37State {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
issue_value: probe.issue_value_lane.raw_u32,
issue_value_hex: probe.issue_value_lane.raw_u32_hex.clone(),
issue_38_value: u32::from(probe.issue_38_raw_u8),
issue_38_value_hex: probe.issue_38_raw_hex.clone(),
issue_39_value: u32::from(probe.issue_39_raw_u8),
issue_39_value_hex: probe.issue_39_raw_hex.clone(),
issue_3a_value: u32::from(probe.issue_3a_raw_u8),
issue_3a_value_hex: probe.issue_3a_raw_hex.clone(),
multiplier_raw_u32: probe.multiplier_lane.raw_u32,
multiplier_raw_hex: probe.multiplier_lane.raw_u32_hex.clone(),
multiplier_value_f32_text: format!("{:.6}", probe.multiplier_lane.value_f32),
issue_opinion_base_terms_raw_i32: probe.issue_opinion_base_terms_raw_i32.clone(),
}
}
fn derive_loaded_world_economic_tuning_state_from_probe(
probe: &SmpSaveWorldEconomicTuningProbe,
) -> SmpLoadedWorldEconomicTuningState {
SmpLoadedWorldEconomicTuningState {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
mirror_raw_u32: probe.mirror_lane.raw_u32,
mirror_raw_hex: probe.mirror_lane.raw_u32_hex.clone(),
mirror_value_f32_text: format!("{:.6}", probe.mirror_lane.value_f32),
lane_raw_u32: probe.tuning_lanes.iter().map(|lane| lane.raw_u32).collect(),
lane_raw_hex: probe
.tuning_lanes
.iter()
.map(|lane| lane.raw_u32_hex.clone())
.collect(),
lane_value_f32_text: probe
.tuning_lanes
.iter()
.map(|lane| format!("{:.6}", lane.value_f32))
.collect(),
}
}
fn derive_loaded_world_finance_neighborhood_state_from_probe(
probe: &SmpSaveWorldFinanceNeighborhoodProbe,
) -> SmpLoadedWorldFinanceNeighborhoodState {
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
.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(),
stock_policy_raw_u8: probe.stock_policy_raw_u8,
stock_policy_raw_hex: probe.stock_policy_raw_hex.clone(),
bond_policy_raw_u8: probe.bond_policy_raw_u8,
bond_policy_raw_hex: probe.bond_policy_raw_hex.clone(),
bankruptcy_policy_raw_u8: probe.bankruptcy_policy_raw_u8,
bankruptcy_policy_raw_hex: probe.bankruptcy_policy_raw_hex.clone(),
dividend_policy_raw_u8: probe.dividend_policy_raw_u8,
dividend_policy_raw_hex: probe.dividend_policy_raw_hex.clone(),
building_density_growth_setting_raw_u32: probe.building_density_growth_setting_lane.raw_u32,
building_density_growth_setting_raw_hex: probe
.building_density_growth_setting_lane
.raw_u32_hex
.clone(),
labels: probe
.dword_candidates
.iter()
.map(|candidate| candidate.label.clone())
.collect(),
relative_offsets: probe
.dword_candidates
.iter()
.map(|candidate| candidate.relative_offset)
.collect(),
relative_offset_hex: probe
.dword_candidates
.iter()
.map(|candidate| candidate.relative_offset_hex.clone())
.collect(),
raw_u32: probe
.dword_candidates
.iter()
.map(|candidate| candidate.raw_u32)
.collect(),
raw_hex: probe
.dword_candidates
.iter()
.map(|candidate| candidate.raw_u32_hex.clone())
.collect(),
value_i32: probe
.dword_candidates
.iter()
.map(|candidate| candidate.value_i32)
.collect(),
value_f32_text: probe
.dword_candidates
.iter()
.map(|candidate| format!("{:.6}", candidate.value_f32))
.collect(),
}
}
fn derive_loaded_world_locomotive_policy_state_from_probes(
post_text_probe: Option<&SmpPostTextFieldNeighborhoodProbe>,
locomotive_policy_probe: Option<&SmpLocomotivePolicyNeighborhoodProbe>,
) -> Option<SmpLoadedWorldLocomotivePolicyState> {
let field_by_name = |name: &str| {
locomotive_policy_probe?
.grounded_field_observations
.iter()
.find(|field| field.field_name == name)
};
let post_text_field_by_name = |name: &str| {
post_text_probe?
.grounded_field_observations
.iter()
.find(|field| field.field_name == name)
};
let selected_year_gap_scalar = field_by_name("selected-year bucket companion scalar");
let linked_site_gate = field_by_name("linked-site removal follow-on gate");
let auto_show_grade = post_text_field_by_name("Auto-Show Grade During Track Lay");
let starting_building_density = post_text_field_by_name("Starting Building Density Level");
let building_density_growth = post_text_field_by_name("Building Density Growth");
let leftover_simulation_time = post_text_field_by_name("leftover simulation time accumulator");
let selected_year_snapshot = post_text_field_by_name("selected-year lane snapshot");
let all_steam = field_by_name("All Steam Locos Avail.");
let all_diesel = field_by_name("All Diesel Locos Avail.");
let all_electric = field_by_name("All Electric Locos Avail.");
let cached_available_rating = field_by_name("cached available-locomotive rating");
Some(SmpLoadedWorldLocomotivePolicyState {
source_kind: locomotive_policy_probe
.map(|probe| probe.source_kind.clone())
.or_else(|| post_text_probe.map(|probe| probe.source_kind.clone()))?,
semantic_family: "world-locomotive-policy".to_string(),
selected_year_gap_scalar_raw_u32: selected_year_gap_scalar
.and_then(|field| field.value_u32),
selected_year_gap_scalar_raw_hex: selected_year_gap_scalar
.and_then(|field| field.value_u32_hex.clone()),
selected_year_gap_scalar_value_f32_text: selected_year_gap_scalar
.and_then(|field| field.probable_f32_le.clone()),
linked_site_removal_follow_on_gate_raw_u8: linked_site_gate
.and_then(|field| field.value_u8),
linked_site_removal_follow_on_gate_raw_hex: linked_site_gate
.and_then(|field| field.value_u8_hex.clone()),
auto_show_grade_during_track_lay_raw_u8: auto_show_grade.and_then(|field| field.value_u8),
auto_show_grade_during_track_lay_raw_hex: auto_show_grade
.and_then(|field| field.value_u8_hex.clone()),
starting_building_density_level_raw_u8: starting_building_density
.and_then(|field| field.value_u8),
starting_building_density_level_raw_hex: starting_building_density
.and_then(|field| field.value_u8_hex.clone()),
building_density_growth_raw_u8: building_density_growth.and_then(|field| field.value_u8),
building_density_growth_raw_hex: building_density_growth
.and_then(|field| field.value_u8_hex.clone()),
leftover_simulation_time_accumulator_raw_u32: leftover_simulation_time
.and_then(|field| field.value_u32),
leftover_simulation_time_accumulator_raw_hex: leftover_simulation_time
.and_then(|field| field.value_u32_hex.clone()),
leftover_simulation_time_accumulator_value_f32_text: leftover_simulation_time
.and_then(|field| field.probable_f32_le.clone()),
selected_year_lane_snapshot_raw_u8: selected_year_snapshot.and_then(|field| field.value_u8),
selected_year_lane_snapshot_raw_hex: selected_year_snapshot
.and_then(|field| field.value_u8_hex.clone()),
all_steam_locomotives_available_raw_u8: all_steam.and_then(|field| field.value_u8),
all_steam_locomotives_available_raw_hex: all_steam
.and_then(|field| field.value_u8_hex.clone()),
all_diesel_locomotives_available_raw_u8: all_diesel.and_then(|field| field.value_u8),
all_diesel_locomotives_available_raw_hex: all_diesel
.and_then(|field| field.value_u8_hex.clone()),
all_electric_locomotives_available_raw_u8: all_electric.and_then(|field| field.value_u8),
all_electric_locomotives_available_raw_hex: all_electric
.and_then(|field| field.value_u8_hex.clone()),
cached_available_locomotive_rating_raw_u32: cached_available_rating
.and_then(|field| field.value_u32),
cached_available_locomotive_rating_raw_hex: cached_available_rating
.and_then(|field| field.value_u32_hex.clone()),
cached_available_locomotive_rating_value_f32_text: cached_available_rating
.and_then(|field| field.probable_f32_le.clone()),
})
}
fn derive_selection_only_company_roster_from_save_world_probe(
probe: &SmpSaveWorldSelectionContextProbe,
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpLoadedCompanyRoster> {
Some(SmpLoadedCompanyRoster {
source_kind: format!("{}-company-selection-only", probe.source_kind),
semantic_family: "scenario-selected-company-context".to_string(),
observed_entry_count: header_probe
.map(|probe| probe.live_record_count as usize)
.unwrap_or(0),
selected_company_id: Some(probe.selected_company_id),
entries: Vec::new(),
})
}
fn derive_selection_only_chairman_profile_table_from_save_world_probe(
probe: &SmpSaveWorldSelectionContextProbe,
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpLoadedChairmanProfileTable> {
Some(SmpLoadedChairmanProfileTable {
source_kind: format!("{}-chairman-selection-only", probe.source_kind),
semantic_family: "scenario-selected-chairman-context".to_string(),
observed_entry_count: header_probe
.map(|probe| probe.live_record_count as usize)
.unwrap_or(0),
selected_chairman_profile_id: Some(probe.selected_chairman_profile_id),
entries: Vec::new(),
})
}
const SAVE_COMPANY_RECORD_NAME_OFFSET: usize = 0x04;
const SAVE_COMPANY_RECORD_NAME_MAX_LEN: usize = 0x24;
const SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET: usize = 0x3b;
const SAVE_COMPANY_RECORD_ACTIVE_OFFSET: usize = 0x3f;
const SAVE_COMPANY_RECORD_OUTSTANDING_SHARES_OFFSET: usize = 0x47;
const SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET: usize = 0x4f;
const SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET: usize = 0x57;
const SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET: usize = 0x5b;
const SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET: usize = 0x5f;
const SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE: usize = 12;
const SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET: usize = 0x14f;
const SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_YEAR_OFFSET: usize = 0x34f;
const SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_AMOUNT_OFFSET: usize = 0x353;
const SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET: usize = 0x15f;
const SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET: usize = 0x157;
const SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET: usize = 0x163;
const SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET: usize = 0x16b;
const SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET_2: usize = 0x16f;
const SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET: usize = 0x173;
const SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET_2: usize = 0x177;
const SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET: usize = 0x289;
const SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET: usize = 0x0d2d;
const SAVE_COMPANY_RECORD_PREFERRED_LOCOMOTIVE_ENGINE_TYPE_OFFSET: usize = 0x0d17;
const SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET: usize = 0x0d18;
const SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET: usize = 0x0d07;
const SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET: usize = 0x0d59;
const SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET: usize = 0x0d56;
const SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET: usize = 0x0d19;
const SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET: usize = 0x0d7b;
const SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET: usize = 0x7680;
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET: usize = 0x0cfb;
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET: usize = 0x0d7f;
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET: usize = 0x1c47;
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS: usize = 32;
const SAVE_COMPANY_RECORD_ISSUE_OPINION_TERMS_OFFSET: usize = 0x2ab;
const SAVE_COMPANY_RECORD_ISSUE_OPINION_TERM_COUNT: usize =
RT3_SAVE_WORLD_BLOCK_ISSUE_OPINION_TERM_COUNT;
const SAVE_COMPANY_RECORD_YEAR_STAT_FAMILY_QWORD_COUNT: usize =
crate::runtime::RUNTIME_COMPANY_STAT_SLOT_COUNT as usize
* crate::runtime::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN as usize;
const SAVE_COMPANY_RECORD_SPECIAL_STAT_FAMILY_232A_QWORD_COUNT: usize =
crate::runtime::RUNTIME_COMPANY_STAT_SLOT_COUNT as usize;
const SAVE_COMPANY_RECORD_DIRECT_CONTROL_TRANSFER_FLOAT_FIELDS: [usize; 10] = [
0x4b, 0x53, 0x323, 0x327, 0x32b, 0x32f, 0x333, 0x337, 0x33b, 0x33f,
];
const SAVE_COMPANY_RECORD_DIRECT_CONTROL_TRANSFER_INT_FIELDS: [usize; 5] =
[0x14f, 0x34b, 0x0d0b, 0x0d0f, 0x0d13];
const SAVE_COMPANY_RECORD_SCALAR_CANDIDATE_FIELDS: [(&str, usize); 9] = [
("mutable_support_scalar", 0x4f),
("young_company_support_scalar", 0x57),
(
"support_progress_word",
SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET,
),
(
"recent_per_share_subscore",
SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET,
),
("cached_share_price", 0x0d7b),
(
"current_issue_calendar_word",
SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET,
),
(
"current_issue_calendar_word_2",
SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET_2,
),
(
"prior_issue_calendar_word",
SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET,
),
(
"prior_issue_calendar_word_2",
SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET_2,
),
];
const SAVE_COMPANY_RECORD_POST_CAPACITY_CANDIDATE_FIELDS: [(&str, usize); 6] = [
("post_capacity_word_1", 0x7684),
("post_capacity_word_2", 0x7688),
("post_capacity_word_3", 0x768c),
("post_capacity_word_4", 0x7690),
("post_capacity_word_5", 0x7694),
("post_capacity_word_6", 0x7698),
];
const SAVE_COMPANY_RECORD_START_SCAN_LIMIT: usize = 0x120;
const SAVE_CHAIRMAN_RECORD_NAME_OFFSET: usize = 0x08;
const SAVE_CHAIRMAN_RECORD_NAME_MAX_LEN: usize = 0x1f;
const SAVE_CHAIRMAN_RECORD_CASH_OFFSET: usize = 0x154;
const SAVE_CHAIRMAN_RECORD_HOLDINGS_BASE_OFFSET: usize = 0x15d;
const SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET: usize = 0x1dd;
const SAVE_CHAIRMAN_RECORD_CACHE_0_OFFSET: usize = 0x1e9;
const SAVE_CHAIRMAN_RECORD_CACHE_1_OFFSET: usize = 0x1f1;
const SAVE_CHAIRMAN_RECORD_PERSONALITY_BYTE_0X291_OFFSET: usize = 0x291;
const SAVE_CHAIRMAN_RECORD_ISSUE_OPINION_TERMS_OFFSET: usize = 0x35b;
const SAVE_CHAIRMAN_RECORD_ISSUE_OPINION_TERM_COUNT: usize =
RT3_SAVE_WORLD_BLOCK_ISSUE_OPINION_TERM_COUNT;
const SAVE_CHAIRMAN_RECORD_CACHE_CANDIDATE_OFFSETS: [usize; 7] =
[0x1e9, 0x1f1, 0x1f9, 0x201, 0x209, 0x211, 0x219];
const SAVE_CHAIRMAN_RECORD_START_SCAN_LIMIT: usize = 0x80;
fn parse_save_company_roster_probe(
bytes: &[u8],
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
selection_probe: Option<&SmpSaveWorldSelectionContextProbe>,
) -> Option<SmpLoadedCompanyRoster> {
let header_probe = header_probe?;
let observed_entry_count = header_probe.live_record_count as usize;
if observed_entry_count == 0 {
return Some(SmpLoadedCompanyRoster {
source_kind: "save-company-direct-records".to_string(),
semantic_family: "scenario-save-company-direct-records".to_string(),
observed_entry_count,
selected_company_id: selection_probe.map(|probe| probe.selected_company_id),
entries: Vec::new(),
});
}
let record_start_offset = detect_save_company_record_start_offset(bytes, header_probe)?;
let record_stride = header_probe.direct_record_stride as usize;
let base_offset = header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(record_start_offset)?;
let mut entries = Vec::with_capacity(observed_entry_count);
for index in 0..observed_entry_count {
let record_offset = base_offset.checked_add(index.checked_mul(record_stride)?)?;
let company_id = read_u32_at(bytes, record_offset)?;
let active = read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_ACTIVE_OFFSET)? != 0;
let linked_chairman_profile_id = parse_nonzero_u32(
bytes,
record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET,
)?;
let outstanding_shares = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_OUTSTANDING_SHARES_OFFSET,
)?;
let debt = parse_save_company_total_debt(bytes, record_offset)?;
let bond_count = read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)?;
let live_bond_slots = parse_save_company_live_bond_slots(bytes, record_offset)?;
let largest_live_bond_principal =
parse_save_company_largest_live_bond_principal(bytes, record_offset)?;
let highest_coupon_live_bond_principal =
parse_save_company_highest_coupon_live_bond_principal(bytes, record_offset)?;
let available_track_laying_capacity =
parse_save_company_available_track_laying_capacity(bytes, record_offset)?;
let mutable_support_scalar_raw_u32 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET,
)?;
let young_company_support_scalar_raw_u32 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET,
)?;
let support_progress_word = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET,
)?;
let recent_per_share_cache_absolute_counter = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET,
)?;
let recent_per_share_cached_value_bits = read_u64_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 4,
)?;
let recent_per_share_subscore_raw_u32 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET,
)?;
let cached_share_price_raw_u32 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET,
)?;
let chairman_salary_baseline = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET,
)?;
let chairman_salary_current = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET,
)?;
let chairman_bonus_year = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_YEAR_OFFSET,
)?;
let chairman_bonus_amount = read_i32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_AMOUNT_OFFSET,
)?;
let founding_year = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET,
)?;
let last_bankruptcy_year = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET,
)?;
let last_dividend_year = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET,
)?;
let current_issue_calendar_word = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET,
)?;
let current_issue_calendar_word_2 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET_2,
)?;
let prior_issue_calendar_word = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET,
)?;
let prior_issue_calendar_word_2 = read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET_2,
)?;
let preferred_locomotive_engine_type_raw_u8 = read_u8_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_PREFERRED_LOCOMOTIVE_ENGINE_TYPE_OFFSET,
)?;
let city_connection_latch = read_u8_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET,
)? != 0;
let linked_transit_latch = read_u8_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET,
)? != 0;
let merger_cooldown_year = parse_nonzero_u32(
bytes,
record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET,
)?;
let takeover_cooldown_year = parse_nonzero_u32(
bytes,
record_offset + SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET,
)?;
let stat_band_root_0cfb_candidates = build_save_company_stat_band_candidates(
bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET,
"stat_band_0cfb",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
let stat_band_root_0d7f_candidates = build_save_company_stat_band_candidates(
bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET,
"stat_band_0d7f",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
let stat_band_root_1c47_candidates = build_save_company_stat_band_candidates(
bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET,
"stat_band_1c47",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
)?;
let year_stat_family_qword_bits = build_save_company_stat_qword_bits(
bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET,
SAVE_COMPANY_RECORD_YEAR_STAT_FAMILY_QWORD_COUNT,
)?;
let special_stat_family_232a_qword_bits = build_save_company_stat_qword_bits(
bytes,
record_offset,
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET,
SAVE_COMPANY_RECORD_SPECIAL_STAT_FAMILY_232A_QWORD_COUNT,
)?;
let direct_control_transfer_float_fields_raw_u32 = build_save_u32_field_map(
bytes,
record_offset,
&SAVE_COMPANY_RECORD_DIRECT_CONTROL_TRANSFER_FLOAT_FIELDS,
)?;
let direct_control_transfer_int_fields_raw_u32 = build_save_u32_field_map(
bytes,
record_offset,
&SAVE_COMPANY_RECORD_DIRECT_CONTROL_TRANSFER_INT_FIELDS,
)?;
let issue_opinion_terms_raw_i32 = build_save_i32_term_strip(
bytes,
record_offset,
SAVE_COMPANY_RECORD_ISSUE_OPINION_TERMS_OFFSET,
SAVE_COMPANY_RECORD_ISSUE_OPINION_TERM_COUNT,
)?;
let current_cash = decode_save_company_current_year_stat_slot(
&year_stat_family_qword_bits,
crate::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
)
.and_then(round_f64_to_i64)
.unwrap_or(0);
entries.push(SmpLoadedCompanyRosterEntry {
company_id,
active,
controller_kind: RuntimeCompanyControllerKind::Unknown,
current_cash,
debt,
credit_rating_score: None,
prime_rate: None,
available_track_laying_capacity,
track_piece_counts: RuntimeTrackPieceCounts::default(),
linked_chairman_profile_id,
book_value_per_share: 0,
investor_confidence: 0,
management_attitude: 0,
takeover_cooldown_year,
merger_cooldown_year,
preferred_locomotive_engine_type_raw_u8: Some(preferred_locomotive_engine_type_raw_u8),
market_state: Some(RuntimeCompanyMarketState {
outstanding_shares,
bond_count,
live_bond_slots,
largest_live_bond_principal,
highest_coupon_live_bond_principal,
mutable_support_scalar_raw_u32,
young_company_support_scalar_raw_u32,
support_progress_word,
recent_per_share_cache_absolute_counter,
recent_per_share_cached_value_bits,
recent_per_share_subscore_raw_u32,
cached_share_price_raw_u32,
chairman_salary_baseline,
chairman_salary_current,
chairman_bonus_year,
chairman_bonus_amount,
founding_year,
last_bankruptcy_year,
last_dividend_year,
current_issue_calendar_word,
current_issue_calendar_word_2,
prior_issue_calendar_word,
prior_issue_calendar_word_2,
city_connection_latch,
linked_transit_latch,
stat_band_root_0cfb_candidates: stat_band_root_0cfb_candidates
.iter()
.map(runtime_company_stat_band_candidate_from_save)
.collect(),
stat_band_root_0d7f_candidates: stat_band_root_0d7f_candidates
.iter()
.map(runtime_company_stat_band_candidate_from_save)
.collect(),
stat_band_root_1c47_candidates: stat_band_root_1c47_candidates
.iter()
.map(runtime_company_stat_band_candidate_from_save)
.collect(),
year_stat_family_qword_bits,
special_stat_family_232a_qword_bits,
issue_opinion_terms_raw_i32,
direct_control_transfer_float_fields_raw_u32,
direct_control_transfer_int_fields_raw_u32,
}),
});
}
Some(SmpLoadedCompanyRoster {
source_kind: "save-company-direct-records".to_string(),
semantic_family: "scenario-save-company-direct-records".to_string(),
observed_entry_count,
selected_company_id: selection_probe.map(|probe| probe.selected_company_id),
entries,
})
}
fn runtime_company_stat_band_candidate_from_save(
candidate: &SmpSaveDwordCandidate,
) -> crate::RuntimeCompanyStatBandCandidate {
crate::RuntimeCompanyStatBandCandidate {
label: candidate.label.clone(),
relative_offset: candidate.relative_offset,
relative_offset_hex: candidate.relative_offset_hex.clone(),
raw_u32: candidate.raw_u32,
raw_u32_hex: candidate.raw_u32_hex.clone(),
value_i32: candidate.value_i32,
value_f32_text: format!("{:.6}", candidate.value_f32),
}
}
fn build_save_company_stat_band_candidates(
bytes: &[u8],
record_offset: usize,
root_offset: usize,
label_prefix: &str,
word_count: usize,
) -> Option<Vec<SmpSaveDwordCandidate>> {
(0..word_count)
.map(|index| {
let relative_offset = root_offset.checked_add(index.checked_mul(4)?)?;
let label = format!("{label_prefix}_word_{}", index + 1);
build_save_dword_candidate(bytes, record_offset, &label, relative_offset)
})
.collect::<Option<Vec<_>>>()
}
fn build_save_company_stat_qword_bits(
bytes: &[u8],
record_offset: usize,
root_offset: usize,
qword_count: usize,
) -> Option<Vec<u64>> {
(0..qword_count)
.map(|index| {
let relative_offset = root_offset.checked_add(index.checked_mul(8)?)?;
read_u64_at(bytes, record_offset + relative_offset)
})
.collect::<Option<Vec<_>>>()
}
fn build_save_i32_term_strip(
bytes: &[u8],
record_offset: usize,
root_offset: usize,
value_count: usize,
) -> Option<Vec<i32>> {
(0..value_count)
.map(|index| {
let relative_offset = root_offset.checked_add(index.checked_mul(4)?)?;
read_i32_at(bytes, record_offset + relative_offset)
})
.collect::<Option<Vec<_>>>()
}
fn build_save_u32_field_map(
bytes: &[u8],
record_offset: usize,
offsets: &[usize],
) -> Option<BTreeMap<u32, u32>> {
let mut fields = BTreeMap::new();
for relative_offset in offsets {
fields.insert(
u32::try_from(*relative_offset).ok()?,
read_u32_at(bytes, record_offset + *relative_offset)?,
);
}
Some(fields)
}
fn decode_save_company_current_year_stat_slot(
year_stat_family_qword_bits: &[u64],
slot_id: u32,
) -> Option<f64> {
let index = slot_id.checked_mul(crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)? as usize;
let value = f64::from_bits(*year_stat_family_qword_bits.get(index)?);
value.is_finite().then_some(value)
}
fn detect_save_company_record_start_offset(
bytes: &[u8],
header_probe: &SmpSaveTaggedCollectionHeaderProbe,
) -> Option<usize> {
let observed_entry_count = header_probe.live_record_count as usize;
let record_stride = header_probe.direct_record_stride as usize;
let scan_limit = SAVE_COMPANY_RECORD_START_SCAN_LIMIT.min(record_stride);
let base_offset = header_probe.metadata_tag_offset.checked_add(4)?;
let mut best_start = None;
let mut best_score = 0usize;
for start in 0..scan_limit {
let mut score = 0usize;
let mut seen_ids = std::collections::BTreeSet::new();
let mut valid = true;
for index in 0..observed_entry_count {
let record_offset = match base_offset
.checked_add(start)
.and_then(|offset| offset.checked_add(index.checked_mul(record_stride)?))
{
Some(offset) => offset,
None => {
valid = false;
break;
}
};
let company_id = match read_u32_at(bytes, record_offset) {
Some(value)
if value >= 1
&& value <= header_probe.live_id_bound
&& seen_ids.insert(value) =>
{
value
}
_ => {
valid = false;
break;
}
};
let active = match read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_ACTIVE_OFFSET)
{
Some(0 | 1) => {
score += 1;
true
}
_ => {
valid = false;
break;
}
};
let linked = match read_u32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET,
) {
Some(value) if value <= 0x100 => value,
_ => {
valid = false;
break;
}
};
let name = match read_ascii_c_string_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_NAME_OFFSET,
SAVE_COMPANY_RECORD_NAME_MAX_LEN,
) {
Some(name) if !name.is_empty() && name.chars().all(is_save_name_char) => name,
_ => {
valid = false;
break;
}
};
score += name.len();
if active {
score += 8;
}
if linked != 0 {
score += 2;
}
if company_id == (index + 1) as u32 {
score += 4;
}
}
if valid && score > best_score {
best_score = score;
best_start = Some(start);
}
}
best_start
}
fn parse_save_company_total_debt(bytes: &[u8], record_offset: usize) -> Option<u64> {
let bond_count =
read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)? as usize;
let mut total = 0u64;
for slot_index in 0..bond_count {
let slot_offset = record_offset
.checked_add(SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET)?
.checked_add(slot_index.checked_mul(SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE)?)?;
let principal = read_i32_at(bytes, slot_offset)?;
if principal > 0 {
total = total.checked_add(principal as u64)?;
}
}
Some(total)
}
fn parse_save_company_live_bond_slots(
bytes: &[u8],
record_offset: usize,
) -> Option<Vec<crate::RuntimeCompanyBondSlot>> {
let bond_count =
read_u8_at(bytes, record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET)? as usize;
let mut slots = Vec::new();
for slot_index in 0..bond_count {
let slot_offset = record_offset
.checked_add(SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET)?
.checked_add(slot_index.checked_mul(SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE)?)?;
let principal = read_i32_at(bytes, slot_offset)?;
if principal <= 0 {
continue;
}
let maturity_year = read_u32_at(bytes, slot_offset + 4)?;
let coupon_rate_raw_u32 = read_u32_at(bytes, slot_offset + 8)?;
let coupon_rate = f32::from_bits(coupon_rate_raw_u32);
if !coupon_rate.is_finite() {
continue;
}
slots.push(crate::RuntimeCompanyBondSlot {
slot_index: slot_index as u32,
principal: principal as u32,
maturity_year,
coupon_rate_raw_u32,
});
}
Some(slots)
}
fn parse_save_company_largest_live_bond_principal(
bytes: &[u8],
record_offset: usize,
) -> Option<Option<u32>> {
let mut largest_live_principal: Option<u32> = None;
for slot in parse_save_company_live_bond_slots(bytes, record_offset)? {
largest_live_principal = Some(match largest_live_principal {
Some(current) => current.max(slot.principal),
None => slot.principal,
});
}
Some(largest_live_principal)
}
fn parse_save_company_highest_coupon_live_bond_principal(
bytes: &[u8],
record_offset: usize,
) -> Option<Option<u32>> {
let mut highest_coupon_principal = None;
let mut highest_coupon_rate = None;
for slot in parse_save_company_live_bond_slots(bytes, record_offset)? {
let coupon_rate = f32::from_bits(slot.coupon_rate_raw_u32);
match highest_coupon_rate {
Some(current_rate) if coupon_rate < current_rate => {}
Some(current_rate) if coupon_rate == current_rate => {
if let Some(current_principal) = highest_coupon_principal {
if slot.principal > current_principal {
highest_coupon_principal = Some(slot.principal);
}
}
}
_ => {
highest_coupon_rate = Some(coupon_rate);
highest_coupon_principal = Some(slot.principal);
}
}
}
Some(highest_coupon_principal)
}
fn parse_save_company_available_track_laying_capacity(
bytes: &[u8],
record_offset: usize,
) -> Option<Option<u32>> {
let raw = read_i32_at(
bytes,
record_offset + SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET,
)?;
if raw < 0 {
Some(None)
} else {
Some(Some(raw as u32))
}
}
fn build_save_dword_candidate(
bytes: &[u8],
record_offset: usize,
label: &str,
relative_offset: usize,
) -> Option<SmpSaveDwordCandidate> {
let raw_u32 = read_u32_at(bytes, record_offset + relative_offset)?;
Some(SmpSaveDwordCandidate {
label: label.to_string(),
relative_offset,
relative_offset_hex: format!("0x{relative_offset:x}"),
raw_u32,
raw_u32_hex: format!("0x{raw_u32:08x}"),
value_i32: raw_u32 as i32,
value_f32: f32::from_bits(raw_u32),
})
}
fn build_save_qword_candidate(
bytes: &[u8],
record_offset: usize,
relative_offset: usize,
) -> Option<SmpSaveScalarCandidate> {
let raw_u64 = read_u64_at(bytes, record_offset + relative_offset)?;
Some(SmpSaveScalarCandidate {
relative_offset,
relative_offset_hex: format!("0x{relative_offset:x}"),
raw_u64,
raw_u64_hex: format!("0x{raw_u64:016x}"),
value_i64: raw_u64 as i64,
value_f64: f64::from_bits(raw_u64),
})
}
fn derive_chairman_holdings_share_price_total(
holdings_by_company: &BTreeMap<u32, u32>,
company_share_prices: &BTreeMap<u32, i64>,
) -> Option<i64> {
let mut total = 0i64;
for (company_id, units) in holdings_by_company {
let share_price = *company_share_prices.get(company_id)?;
total = total.checked_add((*units as i64).checked_mul(share_price)?)?;
}
Some(total)
}
fn derive_chairman_cached_purchasing_power_total(
current_cash: i64,
cached_scalar_candidates: &[SmpSaveScalarCandidate],
) -> Option<i64> {
let strongest_cached_total = cached_scalar_candidates
.iter()
.filter_map(|candidate| round_f64_to_i64(candidate.value_f64))
.filter(|value| *value >= 0)
.max()?;
current_cash.checked_add(strongest_cached_total)
}
fn build_save_world_selection_role_analysis(
probe: &SmpSaveWorldSelectionContextProbe,
) -> SmpSaveWorldSelectionRoleAnalysis {
let chairman_slots = probe
.chairman_slot_selectors
.iter()
.copied()
.zip(probe.chairman_role_gate_bytes.iter().copied())
.enumerate()
.map(|(slot_index, (selector_byte, role_gate_byte))| {
SmpSaveWorldSelectionRoleAnalysisEntry {
slot_index,
selector_byte,
selector_byte_hex: format!("0x{selector_byte:02x}"),
role_gate_byte,
role_gate_byte_hex: format!("0x{role_gate_byte:02x}"),
}
})
.collect();
SmpSaveWorldSelectionRoleAnalysis {
selected_company_id: probe.selected_company_id,
selected_chairman_profile_id: probe.selected_chairman_profile_id,
campaign_override_flag: probe.campaign_override_flag,
campaign_override_flag_hex: probe.campaign_override_flag_hex.clone(),
chairman_slots,
}
}
fn parse_save_chairman_profile_table_probe(
bytes: &[u8],
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
selection_probe: Option<&SmpSaveWorldSelectionContextProbe>,
company_header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpLoadedChairmanProfileTable> {
let header_probe = header_probe?;
let observed_entry_count = header_probe.live_record_count as usize;
if observed_entry_count == 0 {
return Some(SmpLoadedChairmanProfileTable {
source_kind: "save-chairman-profile-direct-records".to_string(),
semantic_family: "scenario-save-chairman-profile-direct-records".to_string(),
observed_entry_count,
selected_chairman_profile_id: selection_probe
.map(|probe| probe.selected_chairman_profile_id),
entries: Vec::new(),
});
}
let record_start_offset =
detect_save_chairman_profile_record_start_offset(bytes, header_probe)?;
let record_stride = header_probe.direct_record_stride as usize;
let base_offset = header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(record_start_offset)?;
let company_id_bound = company_header_probe
.map(|probe| probe.live_id_bound)
.unwrap_or(0);
let mut entries = Vec::with_capacity(observed_entry_count);
for index in 0..observed_entry_count {
let record_offset = base_offset.checked_add(index.checked_mul(record_stride)?)?;
let profile_id = read_u32_at(bytes, record_offset)?;
let active = read_u32_at(bytes, record_offset + 4)? != 0;
let name = read_ascii_c_string_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_NAME_OFFSET,
SAVE_CHAIRMAN_RECORD_NAME_MAX_LEN,
)?;
let current_cash = round_f64_to_i64(read_f64_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_CASH_OFFSET,
)?)?;
let linked_company_id = parse_nonzero_u32(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET,
)?;
let personality_byte_0x291 = read_u8_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_PERSONALITY_BYTE_0X291_OFFSET,
)?;
let cache_0 = round_f64_to_i64(read_f64_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_CACHE_0_OFFSET,
)?)?;
let cache_1 = round_f64_to_i64(read_f64_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_CACHE_1_OFFSET,
)?)?;
let cached_scalar_candidates = SAVE_CHAIRMAN_RECORD_CACHE_CANDIDATE_OFFSETS
.iter()
.map(|relative_offset| {
build_save_qword_candidate(bytes, record_offset, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let issue_opinion_terms_raw_i32 = build_save_i32_term_strip(
bytes,
record_offset,
SAVE_CHAIRMAN_RECORD_ISSUE_OPINION_TERMS_OFFSET,
SAVE_CHAIRMAN_RECORD_ISSUE_OPINION_TERM_COUNT,
)?;
let holdings_value_total = cache_0.max(cache_1).max(0);
let net_worth_total = current_cash.saturating_add(holdings_value_total);
let purchasing_power_total =
derive_chairman_cached_purchasing_power_total(current_cash, &cached_scalar_candidates)
.unwrap_or(net_worth_total);
let mut company_holdings = BTreeMap::new();
for company_id in 1..=company_id_bound {
let slot_offset = record_offset
.checked_add(SAVE_CHAIRMAN_RECORD_HOLDINGS_BASE_OFFSET)?
.checked_add((company_id as usize).checked_mul(4)?)?;
let units = read_u32_at(bytes, slot_offset)?;
if units != 0 {
company_holdings.insert(company_id, units);
}
}
entries.push(SmpLoadedChairmanProfileEntry {
profile_id,
name,
active,
current_cash,
linked_company_id,
company_holdings,
holdings_value_total,
net_worth_total,
purchasing_power_total,
personality_byte_0x291: Some(personality_byte_0x291),
issue_opinion_terms_raw_i32,
});
}
Some(SmpLoadedChairmanProfileTable {
source_kind: "save-chairman-profile-direct-records".to_string(),
semantic_family: "scenario-save-chairman-profile-direct-records".to_string(),
observed_entry_count,
selected_chairman_profile_id: selection_probe
.map(|probe| probe.selected_chairman_profile_id),
entries,
})
}
fn detect_save_chairman_profile_record_start_offset(
bytes: &[u8],
header_probe: &SmpSaveTaggedCollectionHeaderProbe,
) -> Option<usize> {
let observed_entry_count = header_probe.live_record_count as usize;
let record_stride = header_probe.direct_record_stride as usize;
let scan_limit = SAVE_CHAIRMAN_RECORD_START_SCAN_LIMIT.min(record_stride);
let base_offset = header_probe.metadata_tag_offset.checked_add(4)?;
let mut best_start = None;
let mut best_score = 0usize;
for start in 0..scan_limit {
let mut score = 0usize;
let mut seen_ids = std::collections::BTreeSet::new();
let mut valid = true;
for index in 0..observed_entry_count {
let record_offset = match base_offset
.checked_add(start)
.and_then(|offset| offset.checked_add(index.checked_mul(record_stride)?))
{
Some(offset) => offset,
None => {
valid = false;
break;
}
};
let profile_id = match read_u32_at(bytes, record_offset) {
Some(value)
if value >= 1
&& value <= header_probe.live_id_bound
&& seen_ids.insert(value) =>
{
value
}
_ => {
valid = false;
break;
}
};
match read_u32_at(bytes, record_offset + 4) {
Some(0 | 1) => score += 1,
_ => {
valid = false;
break;
}
}
let name = match read_ascii_c_string_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_NAME_OFFSET,
SAVE_CHAIRMAN_RECORD_NAME_MAX_LEN,
) {
Some(name) if !name.is_empty() && name.chars().all(is_save_name_char) => name,
_ => {
valid = false;
break;
}
};
match read_u32_at(
bytes,
record_offset + SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET,
) {
Some(value) if value <= 0x100 => score += (value != 0) as usize,
_ => {
valid = false;
break;
}
}
match read_f64_at(bytes, record_offset + SAVE_CHAIRMAN_RECORD_CASH_OFFSET) {
Some(value) if value.is_finite() && value.abs() < 1.0e12 => {
score += name.len() + 4;
}
_ => {
valid = false;
break;
}
}
if profile_id == (index + 1) as u32 {
score += 4;
}
}
if valid && score > best_score {
best_score = score;
best_start = Some(start);
}
}
best_start
}
fn is_save_name_char(ch: char) -> bool {
ch.is_ascii_alphanumeric()
|| matches!(
ch,
' ' | '&' | '\'' | ',' | '.' | '-' | '/' | '(' | ')' | ':'
)
}
fn known_cargo_slot_definition(slot_id: u32) -> Option<KnownCargoSlotDefinition> {
KNOWN_CARGO_SLOT_DEFINITIONS
.iter()
.copied()
.find(|definition| definition.slot_id == slot_id)
}
fn known_cargo_slot_definition_for_descriptor_id(
descriptor_id: u32,
) -> Option<KnownCargoSlotDefinition> {
KNOWN_CARGO_SLOT_DEFINITIONS
.iter()
.copied()
.find(|definition| definition.descriptor_id == descriptor_id)
}
fn runtime_cargo_class_name(cargo_class: RuntimeCargoClass) -> &'static str {
match cargo_class {
RuntimeCargoClass::Factory => "factory",
RuntimeCargoClass::FarmMine => "farm_mine",
RuntimeCargoClass::Other => "other",
}
}
fn parse_event_runtime_collection_summary(
bytes: &[u8],
container_profile: Option<&SmpContainerProfile>,
save_load_summary: Option<&SmpSaveLoadSummary>,
) -> Option<SmpLoadedEventRuntimeCollectionSummary> {
let metadata_offsets = find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_METADATA_TAG);
let record_offsets = find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_RECORDS_TAG);
let close_offsets = find_u16_le_offsets(bytes, EVENT_RUNTIME_COLLECTION_CLOSE_TAG);
for metadata_tag_offset in metadata_offsets {
let packed_state_version = read_u32_at(bytes, metadata_tag_offset + 2)?;
if packed_state_version != EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION {
continue;
}
let records_tag_offset = record_offsets
.iter()
.copied()
.find(|offset| *offset > metadata_tag_offset + 6)?;
let close_tag_offset = close_offsets
.iter()
.copied()
.find(|offset| *offset > records_tag_offset)?;
let metadata_payload = bytes.get(metadata_tag_offset + 6..records_tag_offset)?;
if metadata_payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
continue;
}
let header_words = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT)
.map(|index| read_u32_at(metadata_payload, index * 4))
.collect::<Option<Vec<_>>>()?;
let direct_collection_flag = header_words[0];
let direct_record_stride = usize::try_from(header_words[1]).ok()?;
let live_id_bound = header_words[4];
let live_record_count = usize::try_from(header_words[5]).ok()?;
if direct_collection_flag == 0 || direct_record_stride == 0 {
continue;
}
let bitset_len = ((usize::try_from(live_id_bound).ok()?).saturating_add(15)) / 8;
let payload_bytes = direct_record_stride.checked_mul(live_record_count)?;
if metadata_payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN + bitset_len {
continue;
}
if metadata_payload.len() < bitset_len + payload_bytes {
continue;
}
let bitset_offset = metadata_payload.len() - bitset_len - payload_bytes;
if bitset_offset < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
continue;
}
let bitset = metadata_payload.get(bitset_offset..bitset_offset + bitset_len)?;
let live_entry_ids = decode_live_entry_ids_from_tombstone_bitset(bitset, live_id_bound)?;
if live_entry_ids.len() != live_record_count {
continue;
}
let records_payload = bytes.get(records_tag_offset + 2..close_tag_offset)?;
let records = parse_event_runtime_record_summaries(
records_payload,
records_tag_offset + 2,
&live_entry_ids,
);
let decoded_record_count = records
.iter()
.filter(|record| record.decode_status != "unsupported_framing")
.count();
let imported_runtime_record_count = records
.iter()
.filter(|record| record.executable_import_ready)
.count();
return Some(SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
mechanism_family: save_load_summary
.map(|summary| summary.mechanism_family.clone())
.unwrap_or_else(|| "unknown".to_string()),
mechanism_confidence: save_load_summary
.map(|summary| summary.mechanism_confidence.clone())
.unwrap_or_else(|| "inferred".to_string()),
container_profile_family: container_profile
.map(|profile| profile.profile_family.clone()),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
packed_state_version,
packed_state_version_hex: format!("0x{packed_state_version:08x}"),
live_id_bound,
live_record_count,
live_entry_ids,
decoded_record_count,
imported_runtime_record_count,
records,
});
}
None
}
fn decode_live_entry_ids_from_tombstone_bitset(
bitset: &[u8],
live_id_bound: u32,
) -> Option<Vec<u32>> {
let ids = decode_live_entry_ids_with_mapping(bitset, live_id_bound, false);
if ids.is_some() {
return ids;
}
decode_live_entry_ids_with_mapping(bitset, live_id_bound, true)
}
fn decode_live_entry_ids_with_mapping(
bitset: &[u8],
live_id_bound: u32,
subtract_one: bool,
) -> Option<Vec<u32>> {
let mut live_entry_ids = Vec::new();
for entry_id in 1..=live_id_bound {
let bit_index = if subtract_one {
entry_id.checked_sub(1)?
} else {
entry_id
};
let byte_index = usize::try_from(bit_index / 8).ok()?;
let bit_mask = 1u8.checked_shl(bit_index % 8).unwrap_or(0);
let tombstone_byte = *bitset.get(byte_index)?;
if tombstone_byte & bit_mask == 0 {
live_entry_ids.push(entry_id);
}
}
Some(live_entry_ids)
}
fn parse_event_runtime_record_summaries(
records_payload: &[u8],
records_payload_offset: usize,
live_entry_ids: &[u32],
) -> Vec<SmpLoadedPackedEventRecordSummary> {
try_parse_synthetic_event_runtime_record_summaries(
records_payload,
records_payload_offset,
live_entry_ids,
)
.or_else(|| {
try_parse_real_event_runtime_record_summaries(
records_payload,
records_payload_offset,
live_entry_ids,
)
})
.unwrap_or_else(|| {
build_unsupported_event_runtime_record_summaries(
live_entry_ids,
"0x4e9a payload did not match the current packed-event record decode harness",
)
})
}
fn try_parse_synthetic_event_runtime_record_summaries(
records_payload: &[u8],
records_payload_offset: usize,
live_entry_ids: &[u32],
) -> Option<Vec<SmpLoadedPackedEventRecordSummary>> {
if !records_payload.starts_with(PACKED_EVENT_RECORDS_SYNTHETIC_MAGIC) {
return None;
}
let mut cursor = PACKED_EVENT_RECORDS_SYNTHETIC_MAGIC.len();
let mut records = Vec::with_capacity(live_entry_ids.len());
for (record_index, live_entry_id) in live_entry_ids.iter().copied().enumerate() {
let record_len = usize::try_from(read_u32_at(records_payload, cursor)?).ok()?;
cursor += 4;
let record_body = records_payload.get(cursor..cursor + record_len)?;
records.push(parse_synthetic_event_runtime_record_summary(
record_body,
records_payload_offset + cursor,
record_index,
live_entry_id,
)?);
cursor += record_len;
}
if cursor != records_payload.len() {
return None;
}
Some(records)
}
fn parse_synthetic_event_runtime_record_summary(
record_body: &[u8],
payload_offset: usize,
record_index: usize,
live_entry_id: u32,
) -> Option<SmpLoadedPackedEventRecordSummary> {
if !record_body.starts_with(PACKED_EVENT_RECORD_SYNTHETIC_MAGIC) {
return None;
}
let mut cursor = PACKED_EVENT_RECORD_SYNTHETIC_MAGIC.len();
let trigger_kind = read_u8_at(record_body, cursor)?;
cursor += 1;
let flags = read_u8_at(record_body, cursor)?;
cursor += 1;
let standalone_condition_row_count = usize::from(read_u8_at(record_body, cursor)?);
cursor += 1;
let action_count = usize::from(read_u8_at(record_body, cursor)?);
cursor += 1;
let mut grouped_effect_row_counts = Vec::with_capacity(4);
for _ in 0..4 {
grouped_effect_row_counts.push(usize::from(read_u8_at(record_body, cursor)?));
cursor += 1;
}
let mut text_bands = Vec::with_capacity(PACKED_EVENT_TEXT_BAND_LABELS.len());
for label in PACKED_EVENT_TEXT_BAND_LABELS {
let packed_len = usize::from(read_u16_at(record_body, cursor)?);
cursor += 2;
let band_bytes = record_body.get(cursor..cursor + packed_len)?;
cursor += packed_len;
text_bands.push(SmpLoadedPackedEventTextBandSummary {
label: label.to_string(),
packed_len,
present: packed_len != 0,
preview: ascii_preview(band_bytes),
});
}
let mut decoded_actions = Vec::with_capacity(action_count);
for _ in 0..action_count {
decoded_actions.push(parse_synthetic_packed_event_action(
record_body,
&mut cursor,
)?);
}
if cursor != record_body.len() {
return None;
}
let executable_import_ready = decoded_actions
.iter()
.all(runtime_effect_supported_for_save_import);
Some(SmpLoadedPackedEventRecordSummary {
record_index,
live_entry_id,
payload_offset: Some(payload_offset),
payload_len: Some(record_body.len()),
decode_status: if executable_import_ready {
"executable".to_string()
} else {
"parity_only".to_string()
},
payload_family: "synthetic_harness".to_string(),
trigger_kind: Some(trigger_kind),
active: Some(flags & 0x01 != 0),
marks_collection_dirty: Some(flags & 0x02 != 0),
one_shot: Some(flags & 0x04 != 0),
compact_control: None,
text_bands,
standalone_condition_row_count,
standalone_condition_rows: Vec::new(),
negative_sentinel_scope: None,
grouped_effect_row_counts,
grouped_effect_rows: Vec::new(),
decoded_conditions: Vec::new(),
decoded_actions,
executable_import_ready,
notes: vec!["decoded from the current synthetic packed-event record harness".to_string()],
})
}
fn try_parse_real_event_runtime_record_summaries(
records_payload: &[u8],
records_payload_offset: usize,
live_entry_ids: &[u32],
) -> Option<Vec<SmpLoadedPackedEventRecordSummary>> {
let mut cursor = 0usize;
let mut records = Vec::with_capacity(live_entry_ids.len());
for (record_index, live_entry_id) in live_entry_ids.iter().copied().enumerate() {
let (record, consumed_len) = parse_real_event_runtime_record_summary(
records_payload.get(cursor..)?,
records_payload_offset + cursor,
record_index,
live_entry_id,
)?;
records.push(record);
cursor += consumed_len;
}
if cursor != records_payload.len() {
return None;
}
Some(records)
}
fn parse_real_event_runtime_record_summary(
record_body: &[u8],
payload_offset: usize,
record_index: usize,
live_entry_id: u32,
) -> Option<(SmpLoadedPackedEventRecordSummary, usize)> {
let mut cursor = 0usize;
let mut text_bands = Vec::with_capacity(PACKED_EVENT_TEXT_BAND_LABELS.len());
for label in PACKED_EVENT_TEXT_BAND_LABELS {
let packed_len = usize::from(read_u16_at(record_body, cursor)?);
cursor += 2;
let band_bytes = record_body.get(cursor..cursor + packed_len)?;
cursor += packed_len;
text_bands.push(SmpLoadedPackedEventTextBandSummary {
label: label.to_string(),
packed_len,
present: packed_len != 0,
preview: ascii_preview(band_bytes),
});
}
let compact_control = parse_optional_real_compact_control_summary(record_body, &mut cursor)?;
if read_u16_at(record_body, cursor)? != PACKED_EVENT_REAL_CONDITION_MARKER {
return None;
}
cursor += 2;
let standalone_condition_row_count = usize::from(read_u16_at(record_body, cursor)?);
cursor += 2;
let mut standalone_condition_rows = Vec::with_capacity(standalone_condition_row_count);
for row_index in 0..standalone_condition_row_count {
let row_bytes = record_body.get(cursor..cursor + PACKED_EVENT_REAL_CONDITION_ROW_LEN)?;
cursor += PACKED_EVENT_REAL_CONDITION_ROW_LEN;
let candidate_name = parse_optional_u16_len_prefixed_string(record_body, &mut cursor)?;
standalone_condition_rows.push(parse_real_condition_row_summary(
row_bytes,
row_index,
candidate_name,
)?);
}
if read_u16_at(record_body, cursor)? != PACKED_EVENT_REAL_GROUPED_EFFECT_MARKER {
return None;
}
cursor += 2;
let mut grouped_effect_row_counts = Vec::with_capacity(4);
for _ in 0..4 {
grouped_effect_row_counts.push(usize::from(read_u16_at(record_body, cursor)?));
cursor += 2;
}
let mut grouped_effect_rows =
Vec::with_capacity(grouped_effect_row_counts.iter().sum::<usize>());
for (group_index, row_count) in grouped_effect_row_counts.iter().copied().enumerate() {
for row_index in 0..row_count {
let row_bytes =
record_body.get(cursor..cursor + PACKED_EVENT_REAL_GROUPED_EFFECT_ROW_LEN)?;
cursor += PACKED_EVENT_REAL_GROUPED_EFFECT_ROW_LEN;
let locomotive_name = parse_optional_u16_len_prefixed_string(record_body, &mut cursor)?;
grouped_effect_rows.push(parse_real_grouped_effect_row_summary(
row_bytes,
group_index,
row_index,
locomotive_name,
)?);
}
}
if let Some(control) = compact_control.as_ref() {
for row in &mut grouped_effect_rows {
let target_subject = derive_real_grouped_target_subject(row, control);
let target_scope_ordinal = control
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied();
row.grouped_target_subject = target_subject
.map(real_grouped_target_subject_name)
.map(str::to_string);
row.grouped_target_scope = derive_real_grouped_target_scope_name(
row,
control,
target_subject,
target_scope_ordinal,
);
let company_target_present = control
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied()
.and_then(real_grouped_company_target)
.is_some();
let chairman_target_present = control
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied()
.is_some_and(real_grouped_chairman_target_supported_in_runtime);
let territory_target_present = control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.is_some_and(|selector| *selector >= 0);
if row.descriptor_id == 15
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
&& !company_target_present
&& !territory_target_present
{
row.notes
.push("retire train row is missing company and territory scope".to_string());
}
if row.descriptor_id == 3
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
&& (!company_target_present || !territory_target_present)
{
row.notes
.push("territory access row is missing company or territory scope".to_string());
}
if matches!(target_subject, Some(RealGroupedTargetSubject::Chairman))
&& !chairman_target_present
{
let ordinal = target_scope_ordinal.unwrap_or(u8::MAX);
row.notes.push(format!(
"chairman row uses unsupported grouped target scope ordinal {ordinal}"
));
}
}
}
let negative_sentinel_scope = compact_control.as_ref().and_then(|control| {
derive_negative_sentinel_scope_summary(&standalone_condition_rows, control)
});
let decoded_conditions =
decode_real_condition_rows(&standalone_condition_rows, negative_sentinel_scope.as_ref());
let decoded_actions = compact_control
.as_ref()
.map(|control| decode_real_grouped_effect_actions(&grouped_effect_rows, control))
.unwrap_or_default();
let ordinary_condition_row_count = standalone_condition_rows
.iter()
.filter(|row| row.raw_condition_id >= 0)
.count();
let executable_import_ready = !grouped_effect_rows.is_empty()
&& decoded_actions.len() == grouped_effect_rows.len()
&& decoded_conditions.len() == ordinary_condition_row_count
&& decoded_actions
.iter()
.all(runtime_effect_supported_for_save_import)
&& decoded_conditions
.iter()
.all(runtime_condition_supported_for_save_import);
let consumed_len = cursor;
Some((
SmpLoadedPackedEventRecordSummary {
record_index,
live_entry_id,
payload_offset: Some(payload_offset),
payload_len: Some(consumed_len),
decode_status: "parity_only".to_string(),
payload_family: "real_packed_v1".to_string(),
trigger_kind: compact_control.as_ref().map(|control| control.mode_byte_0x7ef),
active: None,
marks_collection_dirty: None,
one_shot: compact_control
.as_ref()
.map(|control| control.one_shot_header_0x7f5 != 0),
compact_control,
text_bands,
standalone_condition_row_count,
standalone_condition_rows,
negative_sentinel_scope,
grouped_effect_row_counts,
grouped_effect_rows,
decoded_conditions,
decoded_actions,
executable_import_ready,
notes: vec![
"decoded from grounded real 0x4e9a row framing".to_string(),
"grouped descriptor labels and target masks come from the checked-in effect table recovered around 0x006103a0".to_string(),
],
},
consumed_len,
))
}
fn parse_optional_real_compact_control_summary(
record_body: &[u8],
cursor: &mut usize,
) -> Option<Option<SmpLoadedPackedEventCompactControlSummary>> {
if read_u16_at(record_body, *cursor)? == PACKED_EVENT_REAL_CONDITION_MARKER {
return Some(None);
}
let end = cursor.checked_add(PACKED_EVENT_REAL_COMPACT_CONTROL_LEN)?;
let bytes = record_body.get(*cursor..end)?;
let mut local = 0usize;
let mode_byte_0x7ef = read_u8_at(bytes, local)?;
local += 1;
let primary_selector_0x7f0 = read_u32_at(bytes, local)?;
local += 4;
let grouped_mode_0x7f4 = read_u8_at(bytes, local)?;
local += 1;
let one_shot_header_0x7f5 = read_u32_at(bytes, local)?;
local += 4;
let modifier_flag_0x7f9 = read_u8_at(bytes, local)?;
local += 1;
let modifier_flag_0x7fa = read_u8_at(bytes, local)?;
local += 1;
let mut grouped_target_scope_ordinals_0x7fb = Vec::with_capacity(PACKED_EVENT_REAL_GROUP_COUNT);
for _ in 0..PACKED_EVENT_REAL_GROUP_COUNT {
grouped_target_scope_ordinals_0x7fb.push(read_u8_at(bytes, local)?);
local += 1;
}
let mut grouped_scope_checkboxes_0x7ff = Vec::with_capacity(PACKED_EVENT_REAL_GROUP_COUNT);
for _ in 0..PACKED_EVENT_REAL_GROUP_COUNT {
grouped_scope_checkboxes_0x7ff.push(read_u8_at(bytes, local)?);
local += 1;
}
let summary_toggle_0x800 = read_u8_at(bytes, local)?;
local += 1;
let mut grouped_territory_selectors_0x80f = Vec::with_capacity(PACKED_EVENT_REAL_GROUP_COUNT);
for _ in 0..PACKED_EVENT_REAL_GROUP_COUNT {
grouped_territory_selectors_0x80f.push(read_i32_at(bytes, local)?);
local += 4;
}
if local != bytes.len() {
return None;
}
if read_u16_at(record_body, end)? != PACKED_EVENT_REAL_CONDITION_MARKER {
return None;
}
*cursor = end;
Some(Some(SmpLoadedPackedEventCompactControlSummary {
mode_byte_0x7ef,
primary_selector_0x7f0,
grouped_mode_0x7f4,
one_shot_header_0x7f5,
modifier_flag_0x7f9,
modifier_flag_0x7fa,
grouped_target_scope_ordinals_0x7fb,
grouped_scope_checkboxes_0x7ff,
summary_toggle_0x800,
grouped_territory_selectors_0x80f,
}))
}
fn parse_real_condition_row_summary(
row_bytes: &[u8],
row_index: usize,
candidate_name: Option<String>,
) -> Option<SmpLoadedPackedEventConditionRowSummary> {
let raw_condition_id = read_u32_at(row_bytes, 0)? as i32;
let subtype = read_u8_at(row_bytes, 4)?;
let flag_bytes = row_bytes
.get(5..PACKED_EVENT_REAL_CONDITION_ROW_LEN)?
.to_vec();
let candidate_name_display = candidate_name.clone();
let candidate_name_ref = candidate_name_display.as_deref();
let ordinary_metadata = real_ordinary_condition_metadata(raw_condition_id);
let comparator = ordinary_metadata
.and_then(|_| decode_real_condition_comparator(subtype))
.map(condition_comparator_label);
let metric = ordinary_metadata
.map(|metadata| real_ordinary_condition_metric_label(metadata, candidate_name_ref));
let threshold = ordinary_metadata.and_then(|_| decode_real_condition_threshold(&flag_bytes));
let requires_candidate_name_binding = ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::Numeric(
RealOrdinaryConditionMetric::Territory(_)
| RealOrdinaryConditionMetric::CompanyTerritory(_)
)
) && candidate_name.is_some()
});
let mut notes = Vec::new();
if raw_condition_id < 0 {
notes.push("negative sentinel-style condition row id".to_string());
}
if candidate_name.is_some() {
notes.push("condition row carries candidate-name side string".to_string());
}
if ordinary_metadata.is_none() && raw_condition_id >= 0 {
notes.push(
"ordinary condition id is not yet recovered in the checked-in condition table"
.to_string(),
);
}
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability)
) && candidate_name.is_none()
}) {
notes.push(
"candidate-availability condition row is missing its candidate-name side string"
.to_string(),
);
}
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability
| RealWorldConditionKind::NamedLocomotiveCost
)
) && candidate_name.is_none()
}) {
notes.push("named locomotive condition row is missing its side-string binding".to_string());
}
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot)
) && candidate_name.is_none()
}) {
notes.push(
"named cargo-production condition row is missing its side-string binding".to_string(),
);
}
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::FactoryProductionTotal
| RealWorldConditionKind::FarmMineProductionTotal
| RealWorldConditionKind::OtherCargoProductionTotal
)
)
}) {
notes.push(
"checked-in RT3.lng label is known, but this cargo aggregate condition family is not yet lowered"
.to_string(),
);
}
if ordinary_metadata.is_some_and(|metadata| {
matches!(
metadata.kind,
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot)
) && candidate_name_ref
.and_then(recovered_cargo_production_slot_from_condition_name)
.is_none()
}) {
notes.push(
"named cargo-production condition side string does not yet map to a checked-in cargo slot"
.to_string(),
);
}
Some(SmpLoadedPackedEventConditionRowSummary {
row_index,
raw_condition_id,
subtype,
flag_bytes,
candidate_name,
comparator,
metric,
semantic_family: ordinary_metadata
.map(|metadata| real_ordinary_condition_semantic_family(metadata).to_string()),
semantic_preview: ordinary_metadata.and_then(|metadata| {
threshold.map(|value| {
let comparator_text = decode_real_condition_comparator(subtype)
.map(condition_comparator_symbol)
.unwrap_or("?");
let metric_label =
real_ordinary_condition_metric_label(metadata, candidate_name_ref);
format!("Test {} {} {}", metric_label, comparator_text, value)
})
}),
recovered_cargo_slot: ordinary_metadata.and_then(|metadata| match metadata.kind {
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot) => {
candidate_name_ref.and_then(recovered_cargo_production_slot_from_condition_name)
}
_ => None,
}),
recovered_cargo_class: ordinary_metadata.and_then(|metadata| match metadata.kind {
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot) => {
candidate_name_ref
.and_then(recovered_cargo_production_slot_from_condition_name)
.and_then(known_cargo_slot_definition)
.map(|definition| runtime_cargo_class_name(definition.cargo_class).to_string())
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::FactoryProductionTotal,
) => Some("factory".to_string()),
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::FarmMineProductionTotal,
) => Some("farm_mine".to_string()),
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::OtherCargoProductionTotal,
) => Some("other".to_string()),
_ => None,
}),
requires_candidate_name_binding,
notes,
})
}
fn derive_negative_sentinel_scope_summary(
rows: &[SmpLoadedPackedEventConditionRowSummary],
control: &SmpLoadedPackedEventCompactControlSummary,
) -> Option<SmpLoadedPackedEventNegativeSentinelScopeSummary> {
let source_row_indexes = rows
.iter()
.filter(|row| row.raw_condition_id == -1)
.map(|row| row.row_index)
.collect::<Vec<_>>();
if source_row_indexes.is_empty() {
return None;
}
Some(SmpLoadedPackedEventNegativeSentinelScopeSummary {
company_test_scope: decode_company_condition_test_scope(control.modifier_flag_0x7f9)?,
player_test_scope: decode_player_condition_test_scope(control.modifier_flag_0x7fa)?,
territory_scope_selector_is_0x63: control.primary_selector_0x7f0 == 0x63,
source_row_indexes,
})
}
fn decode_company_condition_test_scope(value: u8) -> Option<RuntimeCompanyConditionTestScope> {
match value {
0 => Some(RuntimeCompanyConditionTestScope::Disabled),
1 => Some(RuntimeCompanyConditionTestScope::AllCompanies),
2 => Some(RuntimeCompanyConditionTestScope::SelectedCompanyOnly),
3 => Some(RuntimeCompanyConditionTestScope::AiCompaniesOnly),
4 => Some(RuntimeCompanyConditionTestScope::HumanCompaniesOnly),
_ => None,
}
}
fn decode_player_condition_test_scope(value: u8) -> Option<RuntimePlayerConditionTestScope> {
match value {
0 => Some(RuntimePlayerConditionTestScope::Disabled),
1 => Some(RuntimePlayerConditionTestScope::AllPlayers),
2 => Some(RuntimePlayerConditionTestScope::SelectedPlayerOnly),
3 => Some(RuntimePlayerConditionTestScope::AiPlayersOnly),
4 => Some(RuntimePlayerConditionTestScope::HumanPlayersOnly),
_ => None,
}
}
fn real_ordinary_condition_metadata(
raw_condition_id: i32,
) -> Option<RealOrdinaryConditionMetadata> {
REAL_ORDINARY_CONDITION_METADATA
.iter()
.copied()
.find(|metadata| metadata.raw_condition_id == raw_condition_id)
.or_else(|| {
known_special_condition_definition_for_label_id(raw_condition_id as u32).map(
|definition| {
let kind = if let Some(world_toggle) =
real_grouped_effect_descriptor_metadata(110 + definition.slot_index as u32)
.filter(|metadata| metadata.parameter_family == "world_flag_toggle")
{
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag {
key: world_toggle.runtime_key.unwrap_or(world_toggle.label),
})
} else {
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::SpecialCondition {
label: definition.label,
},
)
};
RealOrdinaryConditionMetadata {
raw_condition_id,
label: definition.label,
kind,
}
},
)
})
}
fn real_ordinary_condition_metric_label(
metadata: RealOrdinaryConditionMetadata,
candidate_name: Option<&str>,
) -> String {
match metadata.kind {
RealOrdinaryConditionKind::Numeric(_) => metadata.label.to_string(),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::SpecialCondition {
label,
}) => {
format!("Special Condition: {label}")
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability) => {
match candidate_name {
Some(name) => format!("Candidate Availability: {name}"),
None => "Candidate Availability".to_string(),
}
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
) => match candidate_name {
Some(name) => format!("Named Locomotive Availability: {name}"),
None => "Named Locomotive Availability".to_string(),
},
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => {
match candidate_name {
Some(name) => format!("Named Locomotive Cost: {name}"),
None => "Named Locomotive Cost".to_string(),
}
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot) => {
match candidate_name {
Some(name) => format!("Cargo Production: {name}"),
None => "Cargo Production".to_string(),
}
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
"Cargo Production Total".to_string()
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::FactoryProductionTotal) => {
"Factory Production Total".to_string()
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::FarmMineProductionTotal) => {
"Farm/Mine Production Total".to_string()
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::OtherCargoProductionTotal,
) => "Other Cargo Production Total".to_string(),
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
) => "Limited Track Building Amount".to_string(),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
"Territory Access Cost".to_string()
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
"Economic Status".to_string()
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
format!("World Flag: {}", metadata.label)
}
}
}
fn real_ordinary_condition_semantic_family(
metadata: RealOrdinaryConditionMetadata,
) -> &'static str {
match metadata.kind {
RealOrdinaryConditionKind::Numeric(_) => "numeric_threshold",
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
"world_flag_equals"
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability
| RealWorldConditionKind::NamedLocomotiveCost
| RealWorldConditionKind::CargoProductionSlot
| RealWorldConditionKind::CargoProductionTotal
| RealWorldConditionKind::FactoryProductionTotal
| RealWorldConditionKind::FarmMineProductionTotal
| RealWorldConditionKind::OtherCargoProductionTotal
| RealWorldConditionKind::LimitedTrackBuildingAmount
| RealWorldConditionKind::TerritoryAccessCost,
) => "world_scalar_threshold",
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
}
}
fn decode_real_condition_comparator(subtype: u8) -> Option<RuntimeConditionComparator> {
match subtype {
0 => Some(RuntimeConditionComparator::Ge),
1 => Some(RuntimeConditionComparator::Le),
2 => Some(RuntimeConditionComparator::Gt),
3 => Some(RuntimeConditionComparator::Lt),
4 => Some(RuntimeConditionComparator::Eq),
5 => Some(RuntimeConditionComparator::Ne),
_ => None,
}
}
fn decode_real_condition_threshold(flag_bytes: &[u8]) -> Option<i64> {
let raw = flag_bytes.get(0..4)?;
let mut bytes = [0u8; 4];
bytes.copy_from_slice(raw);
Some(i32::from_le_bytes(bytes).into())
}
fn condition_comparator_label(comparator: RuntimeConditionComparator) -> String {
match comparator {
RuntimeConditionComparator::Ge => "ge".to_string(),
RuntimeConditionComparator::Le => "le".to_string(),
RuntimeConditionComparator::Gt => "gt".to_string(),
RuntimeConditionComparator::Lt => "lt".to_string(),
RuntimeConditionComparator::Eq => "eq".to_string(),
RuntimeConditionComparator::Ne => "ne".to_string(),
}
}
fn condition_comparator_symbol(comparator: RuntimeConditionComparator) -> &'static str {
match comparator {
RuntimeConditionComparator::Ge => ">=",
RuntimeConditionComparator::Le => "<=",
RuntimeConditionComparator::Gt => ">",
RuntimeConditionComparator::Lt => "<",
RuntimeConditionComparator::Eq => "==",
RuntimeConditionComparator::Ne => "!=",
}
}
fn parse_real_grouped_effect_row_summary(
row_bytes: &[u8],
group_index: usize,
row_index: usize,
locomotive_name: Option<String>,
) -> Option<SmpLoadedPackedEventGroupedEffectRowSummary> {
let descriptor_id = read_u32_at(row_bytes, 0)?;
let raw_scalar_value = read_u32_at(row_bytes, 4)? as i32;
let opcode = read_u8_at(row_bytes, 8)?;
let value_byte_0x09 = read_u8_at(row_bytes, 9)?;
let value_dword_0x0d = read_u32_at(row_bytes, 0x0d)?;
let value_byte_0x11 = read_u8_at(row_bytes, 0x11)?;
let value_byte_0x12 = read_u8_at(row_bytes, 0x12)?;
let value_word_0x14 = read_u16_at(row_bytes, 0x14)?;
let value_word_0x16 = read_u16_at(row_bytes, 0x16)?;
let descriptor_metadata = real_grouped_effect_descriptor_metadata(descriptor_id);
let mut row_shape = classify_real_grouped_effect_row_shape(
opcode,
raw_scalar_value,
value_byte_0x11,
value_byte_0x12,
value_word_0x14,
value_word_0x16,
)
.to_string();
let mut semantic_family = classify_real_grouped_effect_semantic_family(
opcode,
raw_scalar_value,
value_byte_0x11,
value_byte_0x12,
value_word_0x14,
value_word_0x16,
)
.to_string();
if descriptor_metadata.is_some_and(|metadata| {
matches!(
metadata.parameter_family,
"special_condition_scalar" | "candidate_availability_scalar"
) && opcode == 3
&& value_byte_0x11 == 0
&& value_byte_0x12 == 0
&& value_word_0x14 == 0
&& value_word_0x16 == 0
}) {
row_shape = "scalar_assignment".to_string();
semantic_family = "scalar_assignment".to_string();
}
let mut notes = Vec::new();
if locomotive_name.is_some() {
notes.push("grouped effect row carries locomotive-name side string".to_string());
}
if let Some(metadata) = descriptor_metadata {
if metadata.runtime_status != RealGroupedEffectRuntimeStatus::Executable {
notes.push(format!(
"descriptor is recovered in the checked-in effect table as {} parity",
real_grouped_effect_runtime_status_name(metadata.runtime_status)
));
}
} else {
notes.push("descriptor id not yet recovered in the checked-in effect table".to_string());
}
if let Some(loco_id) = recovered_locomotive_availability_loco_id(descriptor_id) {
notes.push(format!(
"locomotive availability descriptor maps to live locomotive id {loco_id}"
));
}
if let Some(loco_id) = recovered_locomotive_cost_loco_id(descriptor_id) {
notes.push(format!(
"locomotive cost descriptor maps to live locomotive id {loco_id}"
));
}
if let Some(cargo_slot) = recovered_cargo_production_slot(descriptor_id) {
notes.push(format!(
"cargo-production descriptor maps to world production slot {cargo_slot}"
));
}
if let Some(cargo_label) = grounded_named_cargo_production_label(descriptor_id) {
notes.push(format!(
"named cargo production descriptor maps to cargo {cargo_label}"
));
}
if descriptor_metadata.is_some_and(|metadata| metadata.parameter_family == "cargo_price_scalar")
{
if let Some(cargo_label) = grounded_named_cargo_price_label(descriptor_id) {
notes.push(format!(
"named cargo price descriptor maps to cargo {cargo_label}"
));
}
}
Some(SmpLoadedPackedEventGroupedEffectRowSummary {
group_index,
row_index,
descriptor_id,
descriptor_label: descriptor_metadata.map(|metadata| metadata.label.to_string()),
target_mask_bits: descriptor_metadata.map(|metadata| metadata.target_mask_bits),
parameter_family: descriptor_metadata.map(|metadata| metadata.parameter_family.to_string()),
grouped_target_subject: None,
grouped_target_scope: None,
opcode,
raw_scalar_value,
value_byte_0x09,
value_dword_0x0d,
value_byte_0x11,
value_byte_0x12,
value_word_0x14,
value_word_0x16,
row_shape,
semantic_family: Some(semantic_family.clone()),
semantic_preview: Some(build_real_grouped_effect_semantic_preview(
descriptor_metadata.map(|metadata| metadata.label),
&semantic_family,
raw_scalar_value,
value_byte_0x11,
value_byte_0x12,
value_word_0x14,
value_word_0x16,
)),
recovered_cargo_slot: recovered_cargo_production_slot(descriptor_id),
recovered_cargo_class: recovered_cargo_production_slot(descriptor_id)
.and_then(known_cargo_slot_definition)
.map(|definition| runtime_cargo_class_name(definition.cargo_class).to_string()),
recovered_cargo_label: grounded_named_cargo_production_label(descriptor_id)
.or_else(|| {
descriptor_metadata
.filter(|metadata| metadata.parameter_family == "cargo_price_scalar")
.and_then(|_| grounded_named_cargo_price_label(descriptor_id))
})
.map(ToString::to_string),
recovered_locomotive_id: recovered_locomotive_availability_loco_id(descriptor_id)
.or_else(|| recovered_locomotive_cost_loco_id(descriptor_id)),
locomotive_name,
notes,
})
}
fn decode_real_condition_rows(
rows: &[SmpLoadedPackedEventConditionRowSummary],
negative_sentinel_scope: Option<&SmpLoadedPackedEventNegativeSentinelScopeSummary>,
) -> Vec<RuntimeCondition> {
rows.iter()
.filter(|row| row.raw_condition_id >= 0)
.filter_map(|row| decode_real_condition_row(row, negative_sentinel_scope))
.collect()
}
fn decode_real_condition_row(
row: &SmpLoadedPackedEventConditionRowSummary,
negative_sentinel_scope: Option<&SmpLoadedPackedEventNegativeSentinelScopeSummary>,
) -> Option<RuntimeCondition> {
let metadata = real_ordinary_condition_metadata(row.raw_condition_id)?;
let comparator = decode_real_condition_comparator(row.subtype)?;
let value = decode_real_condition_threshold(&row.flag_bytes)?;
match metadata.kind {
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::WorldVariable(index)) => {
Some(RuntimeCondition::WorldVariableThreshold {
index,
comparator,
value,
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Company(metric)) => {
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric,
comparator,
value,
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyVariable(index)) => {
Some(RuntimeCondition::CompanyVariableThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
index,
comparator,
value,
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::PlayerVariable(index)) => {
negative_sentinel_scope.and_then(|scope| {
real_condition_player_target(scope).map(|target| {
RuntimeCondition::PlayerVariableThreshold {
target,
index,
comparator,
value,
}
})
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Chairman(metric)) => {
negative_sentinel_scope.and_then(|scope| {
real_condition_chairman_target(scope).map(|target| {
RuntimeCondition::ChairmanNumericThreshold {
target,
metric,
comparator,
value,
}
})
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::TerritoryVariable(
index,
)) => negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::TerritoryVariableThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
index,
comparator,
value,
}),
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::Territory(metric)) => {
negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::TerritoryNumericThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
})
}
RealOrdinaryConditionKind::Numeric(RealOrdinaryConditionMetric::CompanyTerritory(
metric,
)) => negative_sentinel_scope
.filter(|scope| scope.territory_scope_selector_is_0x63)
.map(|_| RuntimeCondition::CompanyTerritoryNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
territory: RuntimeTerritoryTarget::AllTerritories,
metric,
comparator,
value,
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::SpecialCondition {
label,
}) => Some(RuntimeCondition::SpecialConditionThreshold {
label: label.to_string(),
comparator,
value,
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability) => row
.candidate_name
.as_ref()
.map(|name| RuntimeCondition::CandidateAvailabilityThreshold {
name: name.clone(),
comparator,
value,
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionSlot) => {
row.candidate_name.as_ref().and_then(|name| {
recovered_cargo_production_slot_from_condition_name(name).map(|slot| {
let label = known_cargo_slot_definition(slot)
.map(|definition| definition.label.to_string())
.unwrap_or_else(|| name.clone());
RuntimeCondition::CargoProductionSlotThreshold {
slot,
label,
comparator,
value,
}
})
})
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::NamedLocomotiveAvailability,
) => row.candidate_name.as_ref().map(|name| {
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: name.clone(),
comparator,
value,
}
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => row
.candidate_name
.as_ref()
.map(|name| RuntimeCondition::NamedLocomotiveCostThreshold {
name: name.clone(),
comparator,
value,
}),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
Some(RuntimeCondition::CargoProductionTotalThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::FactoryProductionTotal) => {
Some(RuntimeCondition::FactoryProductionTotalThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::FarmMineProductionTotal) => {
Some(RuntimeCondition::FarmMineProductionTotalThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::OtherCargoProductionTotal,
) => Some(RuntimeCondition::OtherCargoProductionTotalThreshold { comparator, value }),
RealOrdinaryConditionKind::WorldState(
RealWorldConditionKind::LimitedTrackBuildingAmount,
) => Some(RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value }),
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
Some(RuntimeCondition::TerritoryAccessCostThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value })
}
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { key }) => {
decode_world_flag_condition(comparator, value, key)
}
}
}
fn decode_world_flag_condition(
comparator: RuntimeConditionComparator,
value: i64,
key: &'static str,
) -> Option<RuntimeCondition> {
let bool_value = match (comparator, value) {
(RuntimeConditionComparator::Eq, 0) | (RuntimeConditionComparator::Ne, 1) => false,
(RuntimeConditionComparator::Eq, 1) | (RuntimeConditionComparator::Ne, 0) => true,
_ => return None,
};
Some(RuntimeCondition::WorldFlagEquals {
key: key.to_string(),
value: bool_value,
})
}
fn real_condition_chairman_target(
scope: &SmpLoadedPackedEventNegativeSentinelScopeSummary,
) -> Option<RuntimeChairmanTarget> {
match scope.player_test_scope {
RuntimePlayerConditionTestScope::AllPlayers => Some(RuntimeChairmanTarget::AllActive),
RuntimePlayerConditionTestScope::SelectedPlayerOnly => {
Some(RuntimeChairmanTarget::SelectedChairman)
}
RuntimePlayerConditionTestScope::AiPlayersOnly => Some(RuntimeChairmanTarget::AiChairmen),
RuntimePlayerConditionTestScope::HumanPlayersOnly => {
Some(RuntimeChairmanTarget::HumanChairmen)
}
RuntimePlayerConditionTestScope::Disabled => None,
}
}
fn real_condition_player_target(
scope: &SmpLoadedPackedEventNegativeSentinelScopeSummary,
) -> Option<RuntimePlayerTarget> {
match scope.player_test_scope {
RuntimePlayerConditionTestScope::AllPlayers => Some(RuntimePlayerTarget::AllActive),
RuntimePlayerConditionTestScope::SelectedPlayerOnly => {
Some(RuntimePlayerTarget::SelectedPlayer)
}
RuntimePlayerConditionTestScope::AiPlayersOnly => Some(RuntimePlayerTarget::AiPlayers),
RuntimePlayerConditionTestScope::HumanPlayersOnly => {
Some(RuntimePlayerTarget::HumanPlayers)
}
RuntimePlayerConditionTestScope::Disabled => None,
}
}
fn real_grouped_effect_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
recovered_cargo_price_descriptor_metadata(descriptor_id)
.or_else(|| recovered_cargo_economics_descriptor_metadata(descriptor_id))
.or_else(|| recovered_cargo_production_descriptor_metadata(descriptor_id))
.or_else(|| recovered_locomotive_availability_descriptor_metadata(descriptor_id))
.or_else(|| recovered_locomotive_cost_descriptor_metadata(descriptor_id))
.or_else(|| recovered_territory_access_cost_descriptor_metadata(descriptor_id))
.or_else(|| recovered_locomotive_policy_descriptor_metadata(descriptor_id))
.or_else(|| special_condition_world_scalar_descriptor_metadata(descriptor_id))
.or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id))
.or_else(|| {
REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA
.iter()
.copied()
.find(|metadata| metadata.descriptor_id == descriptor_id)
})
.or_else(|| {
checked_in_event_effect_descriptor_rows()
.get(&descriptor_id)
.copied()
})
}
fn recovered_cargo_price_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
(descriptor_id == 105).then_some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Cargo Prices",
target_mask_bits: 0x08,
parameter_family: "cargo_price_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
})
}
fn recovered_cargo_economics_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
match descriptor_id {
177 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Cargo Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
178 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Factory Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
179 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Farm/Mine Production",
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
_ => None,
}
}
const GROUNDED_NAMED_CARGO_PRODUCTION_LABELS: [(&str, &str); 50] = [
("Alcohol", "Alcohol Production"),
("Aluminum", "Aluminum Production"),
("Ammunition", "Ammunition Production"),
("Automobiles", "Automobiles Production"),
("Bauxite", "Bauxite Production"),
("Ceramics", "Ceramics Production"),
("Cheese", "Cheese Production"),
("Chemicals", "Chemicals Production"),
("Clothing", "Clothing Production"),
("Coal", "Coal Production"),
("Coffee", "Coffee Production"),
("Concrete", "Concrete Production"),
("Corn", "Corn Production"),
("Cotton", "Cotton Production"),
("Crystals", "Crystals Production"),
("Diesel", "Diesel Production"),
("Dye", "Dye Production"),
("Electronics", "Electronics Production"),
("Fertilizer", "Fertilizer Production"),
("Furniture", "Furniture Production"),
("Goods", "Goods Production"),
("Grain", "Grain Production"),
("Ingots", "Ingots Production"),
("Iron", "Iron Production"),
("Livestock", "Livestock Production"),
("Logs", "Logs Production"),
("Lumber", "Lumber Production"),
("Machinery", "Machinery Production"),
("Mail", "Mail Production"),
("Meat", "Meat Production"),
("Medicine", "Medicine Production"),
("Milk", "Milk Production"),
("Oil", "Oil Production"),
("Ore", "Ore Production"),
("Paper", "Paper Production"),
("Passengers", "Passengers Production"),
("Plastic", "Plastic Production"),
("Produce", "Produce Production"),
("Pulpwood", "Pulpwood Production"),
("Rice", "Rice Production"),
("Rubber", "Rubber Production"),
("Steel", "Steel Production"),
("Sugar", "Sugar Production"),
("Tires", "Tires Production"),
("Toys", "Toys Production"),
("Troops", "Troops Production"),
("Uranium", "Uranium Production"),
("Waste", "Waste Production"),
("Weapons", "Weapons Production"),
("Wool", "Wool Production"),
];
#[derive(Debug, Deserialize)]
struct CheckedInCargoBindingsArtifact {
bindings: Vec<CheckedInCargoBindingRow>,
}
#[derive(Debug, Deserialize)]
struct CheckedInCargoBindingRow {
descriptor_id: u32,
band: String,
cargo_name: String,
}
fn grounded_named_cargo_price_bindings() -> &'static BTreeMap<u32, (&'static str, &'static str)> {
static BINDINGS: OnceLock<BTreeMap<u32, (&'static str, &'static str)>> = OnceLock::new();
BINDINGS.get_or_init(|| {
let artifact: CheckedInCargoBindingsArtifact = serde_json::from_str(include_str!(
"../../../artifacts/exports/rt3-1.06/event-effects-cargo-bindings.json"
))
.expect("checked-in cargo bindings artifact should parse");
artifact
.bindings
.into_iter()
.filter(|binding| binding.band == "cargo_price_named")
.map(|binding| {
let cargo_name = Box::leak(binding.cargo_name.into_boxed_str()) as &'static str;
let descriptor_label =
Box::leak(format!("{cargo_name} Price").into_boxed_str()) as &'static str;
(binding.descriptor_id, (cargo_name, descriptor_label))
})
.collect()
})
}
pub(crate) fn grounded_named_cargo_price_label(descriptor_id: u32) -> Option<&'static str> {
grounded_named_cargo_price_bindings()
.get(&descriptor_id)
.map(|(cargo_label, _)| *cargo_label)
}
fn grounded_named_cargo_production_label(descriptor_id: u32) -> Option<&'static str> {
let index = descriptor_id.checked_sub(180)? as usize;
GROUNDED_NAMED_CARGO_PRODUCTION_LABELS
.get(index)
.map(|(cargo_label, _)| *cargo_label)
}
fn grounded_named_cargo_production_descriptor_label(descriptor_id: u32) -> Option<&'static str> {
let index = descriptor_id.checked_sub(180)? as usize;
GROUNDED_NAMED_CARGO_PRODUCTION_LABELS
.get(index)
.map(|(_, descriptor_label)| *descriptor_label)
}
fn recovered_cargo_production_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
if let Some(label) = grounded_named_cargo_production_descriptor_label(descriptor_id) {
return Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label,
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
});
}
recovered_cargo_production_label(descriptor_id).map(|label| {
RealGroupedEffectDescriptorMetadata {
descriptor_id,
label,
target_mask_bits: 0x08,
parameter_family: "cargo_production_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}
})
}
fn recovered_cargo_production_slot(descriptor_id: u32) -> Option<u32> {
let slot = descriptor_id.checked_sub(229)?;
(1..=11).contains(&slot).then_some(slot)
}
fn recovered_locomotive_availability_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
if let Some(loco_id) = recovered_locomotive_availability_loco_id(descriptor_id) {
let label = recovered_locomotive_availability_label(loco_id);
let executable_in_runtime = (loco_id as usize) <= GROUNDED_LOCOMOTIVE_PREFIX.len();
return Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label,
target_mask_bits: 0x08,
parameter_family: "locomotive_availability_scalar",
runtime_key: None,
runtime_status: if executable_in_runtime {
RealGroupedEffectRuntimeStatus::Executable
} else {
RealGroupedEffectRuntimeStatus::EvidenceBlocked
},
executable_in_runtime,
});
}
(457..=474)
.contains(&descriptor_id)
.then(|| RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: upper_band_locomotive_availability_label(descriptor_id),
target_mask_bits: 0x08,
parameter_family: "locomotive_availability_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::EvidenceBlocked,
executable_in_runtime: false,
})
}
fn recovered_locomotive_availability_loco_id(descriptor_id: u32) -> Option<u32> {
if (241..=351).contains(&descriptor_id) {
return Some(descriptor_id - 240);
}
None
}
fn grounded_locomotive_name(loco_id: u32) -> Option<&'static str> {
let index = loco_id.checked_sub(1)? as usize;
GROUNDED_LOCOMOTIVE_PREFIX.get(index).copied()
}
fn recovered_locomotive_availability_label(loco_id: u32) -> &'static str {
static LABELS: OnceLock<BTreeMap<u32, &'static str>> = OnceLock::new();
LABELS
.get_or_init(|| {
(1..=111)
.map(|loco_id| {
let label = grounded_locomotive_name(loco_id)
.map(|name| format!("{name} Availability"))
.unwrap_or_else(|| {
format!("Lower-Band Locomotive Availability Slot {loco_id}")
});
(loco_id, Box::leak(label.into_boxed_str()) as &'static str)
})
.collect()
})
.get(&loco_id)
.copied()
.expect("lower-band locomotive availability label should exist")
}
fn upper_band_locomotive_availability_label(descriptor_id: u32) -> &'static str {
static LABELS: OnceLock<BTreeMap<u32, &'static str>> = OnceLock::new();
LABELS
.get_or_init(|| {
(457..=474)
.map(|descriptor_id| {
let label = format!(
"Upper-Band Locomotive Availability Slot {}",
descriptor_id - 456
);
(
descriptor_id,
Box::leak(label.into_boxed_str()) as &'static str,
)
})
.collect()
})
.get(&descriptor_id)
.copied()
.expect("upper-band locomotive availability label should exist")
}
fn recovered_cargo_production_label(descriptor_id: u32) -> Option<&'static str> {
known_cargo_slot_definition_for_descriptor_id(descriptor_id).map(|definition| definition.label)
}
fn recovered_cargo_production_slot_from_condition_name(name: &str) -> Option<u32> {
KNOWN_CARGO_SLOT_DEFINITIONS
.iter()
.find(|definition| definition.label == name)
.map(|definition| definition.slot_id)
}
fn recovered_locomotive_cost_loco_id(descriptor_id: u32) -> Option<u32> {
if (352..=451).contains(&descriptor_id) {
return Some(descriptor_id - 351);
}
None
}
fn recovered_locomotive_cost_label(descriptor_id: u32) -> Option<&'static str> {
static LABELS: OnceLock<BTreeMap<u32, &'static str>> = OnceLock::new();
LABELS
.get_or_init(|| {
(352..=451)
.filter_map(|descriptor_id| {
recovered_locomotive_cost_loco_id(descriptor_id).map(|loco_id| {
let label = grounded_locomotive_name(loco_id)
.map(|name| format!("{name} Cost"))
.unwrap_or_else(|| {
format!("Lower-Band Locomotive Cost Slot {loco_id}")
});
let label = Box::leak(label.into_boxed_str()) as &'static str;
(descriptor_id, label)
})
})
.collect()
})
.get(&descriptor_id)
.copied()
.or_else(|| upper_band_locomotive_cost_label(descriptor_id))
}
fn upper_band_locomotive_cost_label(descriptor_id: u32) -> Option<&'static str> {
static LABELS: OnceLock<BTreeMap<u32, &'static str>> = OnceLock::new();
LABELS
.get_or_init(|| {
(475..=502)
.map(|descriptor_id| {
let label = format!("Upper-Band Locomotive Cost Slot {}", descriptor_id - 474);
(
descriptor_id,
Box::leak(label.into_boxed_str()) as &'static str,
)
})
.collect()
})
.get(&descriptor_id)
.copied()
}
fn recovered_locomotive_cost_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
recovered_locomotive_cost_label(descriptor_id).map(|label| {
let executable_in_runtime = recovered_locomotive_cost_loco_id(descriptor_id)
.is_some_and(|loco_id| (loco_id as usize) <= GROUNDED_LOCOMOTIVE_PREFIX.len());
RealGroupedEffectDescriptorMetadata {
descriptor_id,
label,
target_mask_bits: 0x08,
parameter_family: "locomotive_cost_scalar",
runtime_key: None,
runtime_status: if executable_in_runtime {
RealGroupedEffectRuntimeStatus::Executable
} else {
RealGroupedEffectRuntimeStatus::EvidenceBlocked
},
executable_in_runtime,
}
})
}
fn recovered_territory_access_cost_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
(descriptor_id == 453).then_some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "Territory Access Cost",
target_mask_bits: 0x08,
parameter_family: "territory_access_cost_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
})
}
fn recovered_locomotive_policy_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
match descriptor_id {
454 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Steam Locos Avail.",
target_mask_bits: 0x08,
parameter_family: "world_flag_toggle",
runtime_key: Some("world.all_steam_locos_available"),
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
455 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Diesel Locos Avail.",
target_mask_bits: 0x08,
parameter_family: "world_flag_toggle",
runtime_key: Some("world.all_diesel_locos_available"),
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
456 => Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: "All Electric Locos Avail.",
target_mask_bits: 0x08,
parameter_family: "world_flag_toggle",
runtime_key: Some("world.all_electric_locos_available"),
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
}),
_ => None,
}
}
fn special_condition_world_scalar_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
let slot_index = descriptor_id.checked_sub(110)? as usize;
if slot_index != 12 {
return None;
}
let definition = KNOWN_SPECIAL_CONDITION_DEFINITIONS.get(slot_index)?;
if definition.hidden {
return None;
}
Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: definition.label,
target_mask_bits: 0x08,
parameter_family: "world_track_build_limit_scalar",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
})
}
fn special_condition_world_toggle_descriptor_metadata(
descriptor_id: u32,
) -> Option<RealGroupedEffectDescriptorMetadata> {
let slot_index = descriptor_id.checked_sub(110)? as usize;
if !(1..=34).contains(&slot_index) || matches!(slot_index, 12 | 31) {
return None;
}
let definition = KNOWN_SPECIAL_CONDITION_DEFINITIONS.get(slot_index)?;
if definition.hidden {
return None;
}
Some(RealGroupedEffectDescriptorMetadata {
descriptor_id,
label: definition.label,
target_mask_bits: 0x08,
parameter_family: "world_flag_toggle",
runtime_key: None,
runtime_status: RealGroupedEffectRuntimeStatus::Executable,
executable_in_runtime: true,
})
}
fn classify_real_grouped_effect_semantic_family(
opcode: u8,
raw_scalar_value: i32,
value_byte_0x11: u8,
value_byte_0x12: u8,
value_word_0x14: u16,
value_word_0x16: u16,
) -> &'static str {
if opcode == 8 {
return "multivalue_scalar";
}
if value_byte_0x11 != 0 || value_byte_0x12 != 0 || value_word_0x14 != 0 || value_word_0x16 != 0
{
return "timed_duration";
}
if raw_scalar_value == 0 || raw_scalar_value == 1 {
return "bool_toggle";
}
"scalar_assignment"
}
fn classify_real_grouped_effect_row_shape(
opcode: u8,
raw_scalar_value: i32,
value_byte_0x11: u8,
value_byte_0x12: u8,
value_word_0x14: u16,
value_word_0x16: u16,
) -> &'static str {
if opcode == 8 {
return "multivalue_scalar";
}
if value_byte_0x11 != 0 || value_byte_0x12 != 0 || value_word_0x14 != 0 || value_word_0x16 != 0
{
return "timed_duration";
}
if raw_scalar_value == 0 || raw_scalar_value == 1 {
return "bool_toggle";
}
"scalar_assignment"
}
fn build_real_grouped_effect_semantic_preview(
descriptor_label: Option<&str>,
semantic_family: &str,
raw_scalar_value: i32,
value_byte_0x11: u8,
value_byte_0x12: u8,
value_word_0x14: u16,
value_word_0x16: u16,
) -> String {
let label = descriptor_label.unwrap_or("descriptor");
match semantic_family {
"bool_toggle" => {
let state = if raw_scalar_value == 0 {
"FALSE"
} else {
"TRUE"
};
format!("Set {label} to {state}")
}
"timed_duration" => format!(
"Set {label} to {raw_scalar_value} for {value_word_0x14} years {value_word_0x16} months"
),
"multivalue_scalar" => format!(
"Set {label} to {raw_scalar_value} with aux [{value_byte_0x11}, {value_byte_0x12}, {value_word_0x14}, {value_word_0x16}]"
),
_ => format!("Set {label} to {raw_scalar_value}"),
}
}
fn runtime_candidate_availability_name(label: &str) -> String {
label
.strip_suffix(" Availability")
.unwrap_or(label)
.to_string()
}
fn runtime_world_flag_key(
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
) -> Option<String> {
descriptor_metadata
.runtime_key
.map(str::to_string)
.or_else(|| {
(descriptor_metadata.parameter_family == "world_flag_toggle")
.then(|| runtime_world_flag_key_from_label(descriptor_metadata.label))
})
}
pub(crate) fn runtime_world_flag_key_from_label(label: &str) -> String {
normalize_runtime_world_key(label)
}
fn runtime_world_scalar_key(
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
) -> Option<String> {
descriptor_metadata
.runtime_key
.map(str::to_string)
.or_else(|| {
(descriptor_metadata.parameter_family == "world_scalar_override")
.then(|| normalize_runtime_world_key(descriptor_metadata.label))
})
}
pub(crate) fn runtime_world_scalar_key_from_label(label: &str) -> String {
normalize_runtime_world_key(label)
}
fn normalize_runtime_world_key(label: &str) -> String {
let mut key = String::with_capacity(label.len() + 6);
key.push_str("world.");
let mut last_was_underscore = false;
for ch in label.chars() {
if ch.is_ascii_alphanumeric() {
key.push(ch.to_ascii_lowercase());
last_was_underscore = false;
} else if !last_was_underscore {
key.push('_');
last_was_underscore = true;
}
}
while key.ends_with('_') {
key.pop();
}
key
}
fn real_grouped_company_governance_metric(
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
) -> Option<RuntimeCompanyMetric> {
match descriptor_metadata.label {
"Credit Rating" => Some(RuntimeCompanyMetric::CreditRating),
"Prime Rate" => Some(RuntimeCompanyMetric::PrimeRate),
"Book Value Per Share" => Some(RuntimeCompanyMetric::BookValuePerShare),
"Investor Confidence" => Some(RuntimeCompanyMetric::InvestorConfidence),
"Management Attitude" => Some(RuntimeCompanyMetric::ManagementAttitude),
_ => None,
}
}
fn derive_real_grouped_target_subject(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
compact_control: &SmpLoadedPackedEventCompactControlSummary,
) -> Option<RealGroupedTargetSubject> {
if row.parameter_family.as_deref() == Some("company_governance_scalar") {
return Some(RealGroupedTargetSubject::Company);
}
if row.parameter_family.as_deref() == Some("world_scalar_override") {
return Some(RealGroupedTargetSubject::WholeGame);
}
match row.target_mask_bits {
Some(0x08) => Some(RealGroupedTargetSubject::WholeGame),
Some(0x01) => Some(RealGroupedTargetSubject::Company),
Some(0x04) => Some(RealGroupedTargetSubject::Territory),
Some(0x02) => match compact_control
.grouped_scope_checkboxes_0x7ff
.get(row.group_index)
.copied()
{
Some(2) => Some(RealGroupedTargetSubject::Chairman),
_ => Some(RealGroupedTargetSubject::Player),
},
_ if row.descriptor_id == 3 => Some(RealGroupedTargetSubject::Territory),
_ if row.descriptor_id == 15
&& compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.is_some_and(|selector| *selector >= 0) =>
{
Some(RealGroupedTargetSubject::Territory)
}
_ => None,
}
}
fn real_grouped_target_subject_name(subject: RealGroupedTargetSubject) -> &'static str {
match subject {
RealGroupedTargetSubject::Company => "company",
RealGroupedTargetSubject::Player => "player",
RealGroupedTargetSubject::Chairman => "chairman",
RealGroupedTargetSubject::Territory => "territory",
RealGroupedTargetSubject::WholeGame => "whole_game",
}
}
fn derive_real_grouped_target_scope_name(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
compact_control: &SmpLoadedPackedEventCompactControlSummary,
target_subject: Option<RealGroupedTargetSubject>,
target_scope_ordinal: Option<u8>,
) -> Option<String> {
match target_subject {
Some(RealGroupedTargetSubject::Company) => target_scope_ordinal
.map(real_grouped_company_scope_name)
.map(str::to_string),
Some(RealGroupedTargetSubject::Player) => target_scope_ordinal
.map(real_grouped_player_scope_name)
.map(str::to_string),
Some(RealGroupedTargetSubject::Chairman) => target_scope_ordinal
.map(real_grouped_chairman_scope_name)
.map(str::to_string),
Some(RealGroupedTargetSubject::Territory) => compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.copied()
.filter(|selector| *selector >= 0)
.map(|_| "specified_territories".to_string()),
Some(RealGroupedTargetSubject::WholeGame) => Some("whole_game".to_string()),
None => None,
}
}
fn real_grouped_company_scope_name(ordinal: u8) -> &'static str {
match ordinal {
0 => "condition_true_company",
1 => "selected_company",
2 => "human_companies",
3 => "ai_companies",
_ => "unsupported_company_scope",
}
}
fn real_grouped_player_scope_name(ordinal: u8) -> &'static str {
match ordinal {
0 => "condition_true_player",
1 => "selected_player",
2 => "human_players",
3 => "ai_players",
_ => "unsupported_player_scope",
}
}
fn real_grouped_chairman_scope_name(ordinal: u8) -> &'static str {
match ordinal {
0 => "condition_true_chairman",
1 => "selected_chairman",
2 => "human_chairmen",
3 => "ai_chairmen",
_ => "unsupported_chairman_scope",
}
}
fn runtime_variable_index(descriptor_id: u32) -> Option<u32> {
match descriptor_id {
39..=42 => Some(descriptor_id - 38),
43..=46 => Some(descriptor_id - 42),
47..=50 => Some(descriptor_id - 46),
51..=54 => Some(descriptor_id - 50),
_ => None,
}
}
fn decode_real_grouped_effect_actions(
grouped_effect_rows: &[SmpLoadedPackedEventGroupedEffectRowSummary],
compact_control: &SmpLoadedPackedEventCompactControlSummary,
) -> Vec<RuntimeEffect> {
grouped_effect_rows
.iter()
.filter_map(|row| decode_real_grouped_effect_action(row, compact_control))
.collect()
}
fn decode_real_grouped_effect_action(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
compact_control: &SmpLoadedPackedEventCompactControlSummary,
) -> Option<RuntimeEffect> {
let descriptor_metadata = real_grouped_effect_descriptor_metadata(row.descriptor_id)?;
let target_scope_ordinal = compact_control
.grouped_target_scope_ordinals_0x7fb
.get(row.group_index)
.copied()?;
let target_subject = derive_real_grouped_target_subject(row, compact_control);
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "runtime_variable_scalar"
&& row.row_shape == "scalar_assignment"
{
let index = runtime_variable_index(descriptor_metadata.descriptor_id)?;
return match target_subject {
Some(RealGroupedTargetSubject::WholeGame) => Some(RuntimeEffect::SetWorldVariable {
index,
value: i64::from(row.raw_scalar_value),
}),
Some(RealGroupedTargetSubject::Company) => Some(RuntimeEffect::SetCompanyVariable {
target: real_grouped_company_target(target_scope_ordinal)?,
index,
value: i64::from(row.raw_scalar_value),
}),
Some(RealGroupedTargetSubject::Player) => Some(RuntimeEffect::SetPlayerVariable {
target: real_grouped_player_target(target_scope_ordinal)?,
index,
value: i64::from(row.raw_scalar_value),
}),
Some(RealGroupedTargetSubject::Territory) => compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.copied()
.filter(|selector| *selector >= 0)
.map(|selector| RuntimeEffect::SetTerritoryVariable {
target: RuntimeTerritoryTarget::Ids {
ids: vec![selector as u32],
},
index,
value: i64::from(row.raw_scalar_value),
}),
_ => None,
};
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "company_governance_scalar"
&& row.row_shape == "scalar_assignment"
{
let target = real_grouped_company_target(target_scope_ordinal)?;
let metric = real_grouped_company_governance_metric(descriptor_metadata)?;
return Some(RuntimeEffect::SetCompanyGovernanceScalar {
target,
metric,
value: i64::from(row.raw_scalar_value),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 1
&& row.opcode == 8
&& row.row_shape == "multivalue_scalar"
{
return match target_subject {
Some(RealGroupedTargetSubject::Chairman) => Some(RuntimeEffect::SetChairmanCash {
target: real_grouped_chairman_target(target_scope_ordinal)?,
value: i64::from(row.raw_scalar_value),
}),
_ => Some(RuntimeEffect::SetPlayerCash {
target: real_grouped_player_target(target_scope_ordinal)?,
value: i64::from(row.raw_scalar_value),
}),
};
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 2
&& row.opcode == 8
&& row.row_shape == "multivalue_scalar"
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::SetCompanyCash {
target,
value: i64::from(row.raw_scalar_value),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 3
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
let territory = compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.copied()
.filter(|selector| *selector >= 0)
.map(|selector| RuntimeTerritoryTarget::Ids {
ids: vec![selector as u32],
})?;
return Some(RuntimeEffect::SetCompanyTerritoryAccess {
target,
territory,
value: true,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 8
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetEconomicStatusCode {
value: row.raw_scalar_value,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 108
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetSpecialCondition {
label: descriptor_metadata.label.to_string(),
value: row.raw_scalar_value as u32,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 109
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetCandidateAvailability {
name: runtime_candidate_availability_name(descriptor_metadata.label),
value: row.raw_scalar_value as u32,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 122
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetLimitedTrackBuildingAmount {
value: row.raw_scalar_value,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "world_scalar_override"
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetWorldScalarOverride {
key: runtime_world_scalar_key(descriptor_metadata)?,
value: i64::from(row.raw_scalar_value),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "cargo_price_scalar"
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
{
return match row.descriptor_id {
105 => Some(RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::All,
value: row.raw_scalar_value as u32,
}),
descriptor_id => grounded_named_cargo_price_label(descriptor_id).map(|name| {
RuntimeEffect::SetCargoPriceOverride {
target: RuntimeCargoPriceTarget::Named {
name: name.to_string(),
},
value: row.raw_scalar_value as u32,
}
}),
};
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "cargo_production_scalar"
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
{
return match descriptor_metadata.descriptor_id {
177 => Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::All,
value: row.raw_scalar_value as u32,
}),
178 => Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::Factory,
value: row.raw_scalar_value as u32,
}),
179 => Some(RuntimeEffect::SetCargoProductionOverride {
target: RuntimeCargoProductionTarget::FarmMine,
value: row.raw_scalar_value as u32,
}),
230..=240 => {
let slot = descriptor_metadata.descriptor_id.checked_sub(229)?;
Some(RuntimeEffect::SetCargoProductionSlot {
slot,
value: row.raw_scalar_value as u32,
})
}
_ => None,
};
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "territory_access_cost_scalar"
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
{
return Some(RuntimeEffect::SetTerritoryAccessCost {
value: row.raw_scalar_value as u32,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "world_flag_toggle"
&& row.row_shape == "bool_toggle"
{
return Some(RuntimeEffect::SetWorldFlag {
key: runtime_world_flag_key(descriptor_metadata)?,
value: row.raw_scalar_value != 0,
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 9
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::ConfiscateCompanyAssets { target });
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 13
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::DeactivateCompany { target });
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 14
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
return match target_subject {
Some(RealGroupedTargetSubject::Chairman) => Some(RuntimeEffect::DeactivateChairman {
target: real_grouped_chairman_target(target_scope_ordinal)?,
}),
_ => Some(RuntimeEffect::DeactivatePlayer {
target: real_grouped_player_target(target_scope_ordinal)?,
}),
};
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 16
&& row.row_shape == "scalar_assignment"
&& row.raw_scalar_value >= 0
{
let target = real_grouped_company_target(target_scope_ordinal)?;
return Some(RuntimeEffect::SetCompanyTrackLayingCapacity {
target,
value: Some(row.raw_scalar_value as u32),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.descriptor_id == 15
&& row.row_shape == "bool_toggle"
&& row.raw_scalar_value != 0
{
let company_target = real_grouped_company_target(target_scope_ordinal);
let territory_target = compact_control
.grouped_territory_selectors_0x80f
.get(row.group_index)
.copied()
.filter(|selector| *selector >= 0)
.map(|selector| RuntimeTerritoryTarget::Ids {
ids: vec![selector as u32],
});
if company_target.is_none() && territory_target.is_none() {
return None;
}
return Some(RuntimeEffect::RetireTrains {
company_target,
territory_target,
locomotive_name: row.locomotive_name.clone(),
});
}
None
}
fn real_grouped_company_target(ordinal: u8) -> Option<RuntimeCompanyTarget> {
match ordinal {
0 => Some(RuntimeCompanyTarget::ConditionTrueCompany),
1 => Some(RuntimeCompanyTarget::SelectedCompany),
2 => Some(RuntimeCompanyTarget::HumanCompanies),
3 => Some(RuntimeCompanyTarget::AiCompanies),
_ => None,
}
}
fn real_grouped_player_target(ordinal: u8) -> Option<RuntimePlayerTarget> {
match ordinal {
0 => Some(RuntimePlayerTarget::ConditionTruePlayer),
1 => Some(RuntimePlayerTarget::SelectedPlayer),
2 => Some(RuntimePlayerTarget::HumanPlayers),
3 => Some(RuntimePlayerTarget::AiPlayers),
_ => None,
}
}
fn real_grouped_chairman_target(ordinal: u8) -> Option<RuntimeChairmanTarget> {
match ordinal {
0 => Some(RuntimeChairmanTarget::ConditionTrueChairman),
1 => Some(RuntimeChairmanTarget::SelectedChairman),
2 => Some(RuntimeChairmanTarget::HumanChairmen),
3 => Some(RuntimeChairmanTarget::AiChairmen),
_ => None,
}
}
fn real_grouped_chairman_target_supported_in_runtime(ordinal: u8) -> bool {
real_grouped_chairman_target(ordinal).is_some()
}
fn parse_synthetic_packed_event_action(bytes: &[u8], cursor: &mut usize) -> Option<RuntimeEffect> {
let opcode = read_u8_at(bytes, *cursor)?;
*cursor += 1;
match opcode {
0x01 => {
let key = parse_len_prefixed_string(bytes, cursor)?;
let value = read_u8_at(bytes, *cursor)? != 0;
*cursor += 1;
Some(RuntimeEffect::SetWorldFlag { key, value })
}
0x02 => {
let target = parse_synthetic_company_target(bytes, cursor)?;
let delta = read_i64_at(bytes, *cursor)?;
*cursor += 8;
Some(RuntimeEffect::AdjustCompanyCash { target, delta })
}
0x03 => {
let target = parse_synthetic_company_target(bytes, cursor)?;
let delta = read_i64_at(bytes, *cursor)?;
*cursor += 8;
Some(RuntimeEffect::AdjustCompanyDebt { target, delta })
}
0x04 => {
let name = parse_len_prefixed_string(bytes, cursor)?;
let value = read_u32_at(bytes, *cursor)?;
*cursor += 4;
Some(RuntimeEffect::SetCandidateAvailability { name, value })
}
0x05 => {
let label = parse_len_prefixed_string(bytes, cursor)?;
let value = read_u32_at(bytes, *cursor)?;
*cursor += 4;
Some(RuntimeEffect::SetSpecialCondition { label, value })
}
0x06 => {
let template_len = usize::try_from(read_u32_at(bytes, *cursor)?).ok()?;
*cursor += 4;
let template_bytes = bytes.get(*cursor..*cursor + template_len)?;
let record = parse_synthetic_event_runtime_record_template(template_bytes)?;
*cursor += template_len;
Some(RuntimeEffect::AppendEventRecord {
record: Box::new(record),
})
}
0x07 => {
let record_id = read_u32_at(bytes, *cursor)?;
*cursor += 4;
Some(RuntimeEffect::ActivateEventRecord { record_id })
}
0x08 => {
let record_id = read_u32_at(bytes, *cursor)?;
*cursor += 4;
Some(RuntimeEffect::DeactivateEventRecord { record_id })
}
0x09 => {
let record_id = read_u32_at(bytes, *cursor)?;
*cursor += 4;
Some(RuntimeEffect::RemoveEventRecord { record_id })
}
_ => None,
}
}
fn parse_synthetic_event_runtime_record_template(
bytes: &[u8],
) -> Option<RuntimeEventRecordTemplate> {
if !bytes.starts_with(PACKED_EVENT_RECORD_TEMPLATE_SYNTHETIC_MAGIC) {
return None;
}
let mut cursor = PACKED_EVENT_RECORD_TEMPLATE_SYNTHETIC_MAGIC.len();
let record_id = read_u32_at(bytes, cursor)?;
cursor += 4;
let trigger_kind = read_u8_at(bytes, cursor)?;
cursor += 1;
let flags = read_u8_at(bytes, cursor)?;
cursor += 1;
let action_count = usize::from(read_u8_at(bytes, cursor)?);
cursor += 1;
cursor += 1;
let mut effects = Vec::with_capacity(action_count);
for _ in 0..action_count {
effects.push(parse_synthetic_packed_event_action(bytes, &mut cursor)?);
}
if cursor != bytes.len() {
return None;
}
Some(RuntimeEventRecordTemplate {
record_id,
trigger_kind,
active: flags & 0x01 != 0,
marks_collection_dirty: flags & 0x02 != 0,
one_shot: flags & 0x04 != 0,
conditions: Vec::new(),
effects,
})
}
fn parse_synthetic_company_target(
bytes: &[u8],
cursor: &mut usize,
) -> Option<RuntimeCompanyTarget> {
let target_kind = read_u8_at(bytes, *cursor)?;
*cursor += 1;
match target_kind {
0x00 => Some(RuntimeCompanyTarget::AllActive),
0x01 => {
let count = usize::from(read_u8_at(bytes, *cursor)?);
*cursor += 1;
let mut ids = Vec::with_capacity(count);
for _ in 0..count {
ids.push(read_u32_at(bytes, *cursor)?);
*cursor += 4;
}
Some(RuntimeCompanyTarget::Ids { ids })
}
_ => None,
}
}
fn parse_len_prefixed_string(bytes: &[u8], cursor: &mut usize) -> Option<String> {
let len = usize::from(read_u8_at(bytes, *cursor)?);
*cursor += 1;
let text_bytes = bytes.get(*cursor..*cursor + len)?;
*cursor += len;
Some(String::from_utf8_lossy(text_bytes).into_owned())
}
fn parse_optional_u16_len_prefixed_string(
bytes: &[u8],
cursor: &mut usize,
) -> Option<Option<String>> {
let len = usize::from(read_u16_at(bytes, *cursor)?);
*cursor += 2;
if len == 0 {
return Some(None);
}
let text_bytes = bytes.get(*cursor..*cursor + len)?;
*cursor += len;
Some(Some(String::from_utf8_lossy(text_bytes).into_owned()))
}
fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
match effect {
RuntimeEffect::SetChairmanCash { target, .. }
| RuntimeEffect::DeactivateChairman { target } => matches!(
target,
RuntimeChairmanTarget::AllActive
| RuntimeChairmanTarget::HumanChairmen
| RuntimeChairmanTarget::AiChairmen
| RuntimeChairmanTarget::SelectedChairman
| RuntimeChairmanTarget::ConditionTrueChairman
| RuntimeChairmanTarget::Ids { .. }
),
RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetWorldVariable { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetCompanyGovernanceScalar { .. }
| RuntimeEffect::SetCandidateAvailability { .. }
| RuntimeEffect::SetNamedLocomotiveAvailability { .. }
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
| RuntimeEffect::SetNamedLocomotiveCost { .. }
| RuntimeEffect::SetCargoPriceOverride { .. }
| RuntimeEffect::SetCargoProductionOverride { .. }
| RuntimeEffect::SetCargoProductionSlot { .. }
| RuntimeEffect::SetWorldScalarOverride { .. }
| RuntimeEffect::SetTerritoryAccessCost { .. }
| RuntimeEffect::SetSpecialCondition { .. }
| RuntimeEffect::ConfiscateCompanyAssets { .. }
| RuntimeEffect::DeactivateCompany { .. }
| RuntimeEffect::DeactivatePlayer { .. }
| RuntimeEffect::SetCompanyTrackLayingCapacity { .. }
| RuntimeEffect::RetireTrains { .. }
| RuntimeEffect::ActivateEventRecord { .. }
| RuntimeEffect::DeactivateEventRecord { .. }
| RuntimeEffect::RemoveEventRecord { .. } => true,
RuntimeEffect::SetPlayerCash { target, .. }
| RuntimeEffect::SetPlayerVariable { target, .. } => matches!(
target,
RuntimePlayerTarget::AllActive
| RuntimePlayerTarget::Ids { .. }
| RuntimePlayerTarget::HumanPlayers
| RuntimePlayerTarget::AiPlayers
| RuntimePlayerTarget::SelectedPlayer
| RuntimePlayerTarget::ConditionTruePlayer
),
RuntimeEffect::SetCompanyTerritoryAccess {
target, territory, ..
} => {
matches!(
target,
RuntimeCompanyTarget::AllActive
| RuntimeCompanyTarget::Ids { .. }
| RuntimeCompanyTarget::HumanCompanies
| RuntimeCompanyTarget::AiCompanies
| RuntimeCompanyTarget::SelectedCompany
| RuntimeCompanyTarget::ConditionTrueCompany
) && matches!(
territory,
RuntimeTerritoryTarget::AllTerritories | RuntimeTerritoryTarget::Ids { .. }
)
}
RuntimeEffect::SetCompanyCash { target, .. }
| RuntimeEffect::SetCompanyVariable { target, .. }
| RuntimeEffect::AdjustCompanyCash { target, .. }
| RuntimeEffect::AdjustCompanyDebt { target, .. } => matches!(
target,
RuntimeCompanyTarget::AllActive
| RuntimeCompanyTarget::Ids { .. }
| RuntimeCompanyTarget::HumanCompanies
| RuntimeCompanyTarget::AiCompanies
| RuntimeCompanyTarget::SelectedCompany
| RuntimeCompanyTarget::ConditionTrueCompany
),
RuntimeEffect::SetTerritoryVariable { target, .. } => matches!(
target,
RuntimeTerritoryTarget::AllTerritories | RuntimeTerritoryTarget::Ids { .. }
),
RuntimeEffect::AppendEventRecord { record } => record
.effects
.iter()
.all(runtime_effect_supported_for_save_import),
}
}
fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) -> bool {
match condition {
RuntimeCondition::WorldVariableThreshold { .. }
| RuntimeCondition::CompanyNumericThreshold { .. }
| RuntimeCondition::CompanyVariableThreshold { .. }
| RuntimeCondition::PlayerVariableThreshold { .. }
| RuntimeCondition::ChairmanNumericThreshold { .. }
| RuntimeCondition::TerritoryNumericThreshold { .. }
| RuntimeCondition::TerritoryVariableThreshold { .. }
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
| RuntimeCondition::SpecialConditionThreshold { .. }
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
| RuntimeCondition::CargoProductionSlotThreshold { .. }
| RuntimeCondition::CargoProductionTotalThreshold { .. }
| RuntimeCondition::FactoryProductionTotalThreshold { .. }
| RuntimeCondition::FarmMineProductionTotalThreshold { .. }
| RuntimeCondition::OtherCargoProductionTotalThreshold { .. }
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
| RuntimeCondition::WorldFlagEquals { .. } => true,
}
}
fn build_unsupported_event_runtime_record_summaries(
live_entry_ids: &[u32],
note: &str,
) -> Vec<SmpLoadedPackedEventRecordSummary> {
live_entry_ids
.iter()
.copied()
.enumerate()
.map(
|(record_index, live_entry_id)| SmpLoadedPackedEventRecordSummary {
record_index,
live_entry_id,
payload_offset: None,
payload_len: None,
decode_status: "unsupported_framing".to_string(),
payload_family: "unsupported_framing".to_string(),
trigger_kind: None,
active: None,
marks_collection_dirty: None,
one_shot: None,
compact_control: None,
text_bands: Vec::new(),
standalone_condition_row_count: 0,
standalone_condition_rows: Vec::new(),
negative_sentinel_scope: None,
grouped_effect_row_counts: vec![0, 0, 0, 0],
grouped_effect_rows: Vec::new(),
decoded_conditions: Vec::new(),
decoded_actions: Vec::new(),
executable_import_ready: false,
notes: vec![note.to_string()],
},
)
.collect()
}
fn inspect_bundle_bytes(bytes: &[u8], file_extension_hint: Option<String>) -> SmpInspectionReport {
let known_tag_hits = KNOWN_TAG_DEFINITIONS
.iter()
.filter_map(|definition| {
let offsets = find_u16_le_offsets(bytes, definition.tag_id);
if offsets.is_empty() {
return None;
}
Some(SmpKnownTagHit {
tag_id: definition.tag_id,
tag_hex: format!("0x{:04x}", definition.tag_id),
label: definition.label.to_string(),
grounded_meaning: definition.grounded_meaning.to_string(),
hit_count: offsets.len(),
sample_offsets: offsets
.iter()
.copied()
.take(TAG_OFFSET_SAMPLE_LIMIT)
.collect(),
last_offset: offsets.last().copied(),
})
})
.collect::<Vec<_>>();
let shared_header = parse_shared_header(bytes);
let header_variant_probe = shared_header.as_ref().map(classify_header_variant_probe);
let first_ascii_run = find_first_ascii_run(bytes);
let early_content_probe = first_ascii_run
.as_ref()
.and_then(|ascii_run| probe_early_content_layout(bytes, ascii_run));
let secondary_variant_probe = early_content_probe
.as_ref()
.and_then(classify_secondary_variant_probe);
let container_profile = classify_container_profile(
file_extension_hint.as_deref(),
header_variant_probe.as_ref(),
secondary_variant_probe.as_ref(),
);
let runtime_anchor_cycle_block = parse_runtime_anchor_cycle_block(
bytes,
container_profile.as_ref(),
secondary_variant_probe.as_ref(),
);
let save_bootstrap_block =
parse_save_bootstrap_block(container_profile.as_ref(), secondary_variant_probe.as_ref());
let save_anchor_run_block = parse_save_anchor_run_block(
bytes,
container_profile.as_ref(),
save_bootstrap_block.as_ref(),
);
let runtime_trailer_block = parse_runtime_trailer_block(
container_profile.as_ref(),
runtime_anchor_cycle_block.as_ref(),
);
let runtime_post_span_probe =
parse_runtime_post_span_probe(bytes, runtime_trailer_block.as_ref());
let rt3_105_packed_profile_probe = parse_rt3_105_packed_profile_probe(
bytes,
file_extension_hint.as_deref(),
header_variant_probe.as_ref(),
container_profile.as_ref(),
);
let rt3_105_post_span_bridge_probe = parse_rt3_105_post_span_bridge_probe(
runtime_trailer_block.as_ref(),
runtime_post_span_probe.as_ref(),
rt3_105_packed_profile_probe.as_ref(),
);
let rt3_105_save_bridge_payload_probe =
parse_rt3_105_save_bridge_payload_probe(bytes, rt3_105_post_span_bridge_probe.as_ref());
let save_world_selection_context_probe = parse_save_world_selection_context_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_world_issue_37_probe = parse_save_world_issue_37_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_world_economic_tuning_probe = parse_save_world_economic_tuning_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_world_finance_neighborhood_probe = parse_save_world_finance_neighborhood_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_company_collection_header_probe = parse_save_company_collection_header_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_chairman_profile_collection_header_probe =
parse_save_chairman_profile_collection_header_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_train_collection_header_probe = parse_save_train_collection_header_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_train_collection_directory_probe = parse_save_train_collection_directory_probe(
bytes,
save_train_collection_header_probe.as_ref(),
);
let save_region_collection_header_probe = parse_save_region_collection_header_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_region_record_triplet_probe =
parse_save_region_record_triplet_probe(bytes, save_region_collection_header_probe.as_ref());
let save_region_queued_notice_record_probe = parse_save_region_queued_notice_record_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
save_region_collection_header_probe.as_ref(),
);
let save_region_fixed_row_run_candidate_probe = parse_save_region_fixed_row_run_candidate_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
save_region_collection_header_probe.as_ref(),
);
let save_placed_structure_collection_header_probe =
parse_save_placed_structure_collection_header_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let save_placed_structure_record_triplet_probe =
parse_save_placed_structure_record_triplet_probe(
bytes,
save_placed_structure_collection_header_probe.as_ref(),
);
let save_placed_structure_dynamic_side_buffer_probe =
parse_save_placed_structure_dynamic_side_buffer_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let known_header_probes = [
save_company_collection_header_probe.as_ref(),
save_chairman_profile_collection_header_probe.as_ref(),
save_train_collection_header_probe.as_ref(),
save_region_collection_header_probe.as_ref(),
save_placed_structure_collection_header_probe.as_ref(),
];
let save_unclassified_tagged_collection_header_probes =
filter_unclassified_tagged_collection_header_probes_outside_known_spans(
scan_save_unclassified_tagged_collection_header_probes(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
),
&known_header_probes,
);
let save_company_roster_probe = parse_save_company_roster_probe(
bytes,
save_company_collection_header_probe.as_ref(),
save_world_selection_context_probe.as_ref(),
);
let save_chairman_profile_table_probe = parse_save_chairman_profile_table_probe(
bytes,
save_chairman_profile_collection_header_probe.as_ref(),
save_world_selection_context_probe.as_ref(),
save_company_collection_header_probe.as_ref(),
);
let rt3_105_save_name_table_probe = parse_rt3_105_save_name_table_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
rt3_105_save_bridge_payload_probe.as_ref(),
);
let rt3_105_save_named_locomotive_availability_probe =
parse_rt3_105_save_named_locomotive_availability_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
rt3_105_packed_profile_probe.as_ref(),
);
let special_conditions_probe = parse_special_conditions_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
);
let smp_aligned_runtime_rule_band_probe = parse_smp_aligned_runtime_rule_band_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let post_special_conditions_scalar_probe = parse_post_special_conditions_scalar_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let post_text_field_neighborhood_probe = parse_post_text_field_neighborhood_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let locomotive_policy_neighborhood_probe = parse_locomotive_policy_neighborhood_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let pre_recipe_scalar_plateau_probe = parse_pre_recipe_scalar_plateau_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let recipe_book_summary_probe = parse_recipe_book_summary_probe(
bytes,
file_extension_hint.as_deref(),
container_profile.as_ref(),
special_conditions_probe.as_ref(),
);
let classic_rehydrate_profile_probe =
parse_classic_rehydrate_profile_probe(bytes, runtime_post_span_probe.as_ref());
let save_load_summary = build_save_load_summary(
file_extension_hint.as_deref(),
container_profile.as_ref(),
runtime_trailer_block.as_ref(),
rt3_105_post_span_bridge_probe.as_ref(),
classic_rehydrate_profile_probe.as_ref(),
rt3_105_packed_profile_probe.as_ref(),
rt3_105_save_name_table_probe.as_ref(),
);
let event_runtime_collection_summary = parse_event_runtime_collection_summary(
bytes,
container_profile.as_ref(),
save_load_summary.as_ref(),
);
let mut warnings = Vec::new();
if bytes.is_empty() {
warnings
.push("File is empty, so no `.smp` container structure could be observed.".to_string());
}
if known_tag_hits.is_empty() {
warnings.push(
"No grounded runtime bundle tags were found in little-endian form. This does not prove the file is invalid."
.to_string(),
);
}
if shared_header.is_none() && !bytes.is_empty() {
warnings.push(
"File is shorter than the observed 64-byte common RT3 bundle preamble.".to_string(),
);
}
if let Some(shared_header) = &shared_header {
let header_family_is_known = header_variant_probe
.as_ref()
.map(|probe| probe.is_known_family)
.unwrap_or(false);
if !shared_header.matches_grounded_common_signature && !header_family_is_known {
warnings.push(
"The first 64-byte preamble does not match the currently observed shared RT3 bundle signature."
.to_string(),
);
}
}
if first_ascii_run.is_some() && early_content_probe.is_none() {
warnings.push(
"Found early text content but could not resolve the next stable nonzero region after its zero padding."
.to_string(),
);
}
if container_profile
.as_ref()
.is_some_and(|profile| !profile.is_known_profile)
{
warnings.push(
"The current probes did not match any known composite container profile.".to_string(),
);
}
if known_tag_hits
.iter()
.any(|hit| hit.hit_count > hit.sample_offsets.len())
{
warnings.push(
"Known-tag offsets are sampled in this report. Large hit counts usually mean byte-pattern noise, not validated chunk boundaries."
.to_string(),
);
}
warnings.push(
"Inspection scans raw bytes for a small grounded tag set only. It does not validate bundle layout or decode payloads."
.to_string(),
);
SmpInspectionReport {
inspection_mode: "grounded-tag-scan-plus-preamble".to_string(),
file_extension_hint,
file_size: bytes.len(),
sha256: sha256_hex(bytes),
preamble: parse_preamble(bytes),
shared_header,
header_variant_probe,
first_ascii_run,
early_content_probe,
secondary_variant_probe,
container_profile,
save_bootstrap_block,
save_anchor_run_block,
runtime_anchor_cycle_block,
runtime_trailer_block,
runtime_post_span_probe,
rt3_105_post_span_bridge_probe,
rt3_105_save_bridge_payload_probe,
save_world_selection_context_probe,
save_world_issue_37_probe,
save_world_economic_tuning_probe,
save_world_finance_neighborhood_probe,
save_company_collection_header_probe,
save_chairman_profile_collection_header_probe,
save_train_collection_header_probe,
save_train_collection_directory_probe,
save_region_collection_header_probe,
save_region_record_triplet_probe,
save_region_queued_notice_record_probe,
save_region_fixed_row_run_candidate_probe,
save_placed_structure_collection_header_probe,
save_placed_structure_record_triplet_probe,
save_placed_structure_dynamic_side_buffer_probe,
save_unclassified_tagged_collection_header_probes,
save_company_roster_probe,
save_chairman_profile_table_probe,
rt3_105_save_name_table_probe,
rt3_105_save_named_locomotive_availability_probe,
special_conditions_probe,
smp_aligned_runtime_rule_band_probe,
post_special_conditions_scalar_probe,
post_text_field_neighborhood_probe,
locomotive_policy_neighborhood_probe,
pre_recipe_scalar_plateau_probe,
recipe_book_summary_probe,
classic_rehydrate_profile_probe,
rt3_105_packed_profile_probe,
save_load_summary,
event_runtime_collection_summary,
contains_grounded_runtime_tags: !known_tag_hits.is_empty(),
known_tag_hits,
notes: vec![
"Grounded `.smp` runtime tags currently include mask-plane payload ids 0x2cee and 0x2d51.".to_string(),
"Grounded sidecar-byte-plane bundle family currently spans 0x9471..0x9472.".to_string(),
"The shared-header parse is intentionally conservative: it only names common preamble lanes and checks the observed RT3 bundle-family signature.".to_string(),
"The header-variant probe classifies the preamble into one of the currently observed install-era families when possible."
.to_string(),
"The early-content probe resolves the first stable nonzero block after the padded scenario text and then captures the next aligned word window."
.to_string(),
"The secondary-variant probe classifies that aligned word window into one of the currently observed file-family patterns."
.to_string(),
"The recipe-book summary probe reports per-book structural signatures at the grounded recipe-book root [world+0x0fe7] without attempting a full cargo-line decode."
.to_string(),
"Where a recipe cargo-token word looks like two printable letters in its high 16 bits, the probe exposes that as one probable ASCII stem while still treating the wider token semantics as inferred."
.to_string(),
"The container-profile layer combines extension hint, header family, and second-window family into one observed container classification."
.to_string(),
"The save-bootstrap reader currently parses one conservative 8-word descriptor only for known save-container profiles."
.to_string(),
"The save-anchor-run reader follows that descriptor tail into the observed repeated 9-word anchor cycle and captures the first trailer words after the cycle diverges."
.to_string(),
"The runtime-anchor-cycle reader applies the same cycle/trailer scan across the currently known save and sandbox runtime container profiles."
.to_string(),
"The runtime-trailer reader classifies the first 16 words after the cycle divergence into the currently observed runtime trailer families."
.to_string(),
"The runtime post-span probe follows the trailer's high-16 span lane into the later file region and records the next nonzero bytes, the first aligned high-16-dense candidate window, and any grounded progress-id hits found nearby."
.to_string(),
"The RT3 1.05 post-span bridge probe correlates the trailer selector/descriptor lanes with the next candidate region and the later packed-profile block for the currently observed 1.05 save families."
.to_string(),
"The RT3 1.05 common-save bridge payload probe captures the two stable bridge-stage blocks currently observed under the base 1.05 save branch."
.to_string(),
"The RT3 1.05 candidate-availability table probe decodes the fixed-width trailing name table from either the common-save bridge payload or the fixed 0x6a70..0x73c0 source range when that header validates."
.to_string(),
"The RT3 1.05 save-side named locomotive availability probe scans the post-profile save region for the grounded fixed-width locomotive-name-plus-dword row family when that run is present."
.to_string(),
"The post-special-conditions scalar probe captures the fixed 0x0df4..0x0f30 dword window immediately after the hidden sentinel slot, splits it into the aligned-band overlap prefix and the later tail, and records the live-object offset alignment of that tail without claiming a byte-for-byte mirror."
.to_string(),
"The classic rehydrate-profile probe recognizes the grounded 0x32dc -> 0x3714 -> 0x3715 progress-id sequence and captures the exact 0x108-byte block between the latter two ids when that pattern appears."
.to_string(),
"The classic packed-profile block reader exposes the stable map-path, display-name, atlas-tracked latch bytes, and the small set of nonzero word lanes observed inside that 0x108-byte block."
.to_string(),
"The RT3 1.05 packed-profile probe recognizes the later string-bearing save block rooted at the first post-header .gmp path and exposes the observed map-path, display-name, atlas-tracked byte lanes, and stable nonzero words."
.to_string(),
format!(
"Restore-side loading of the four sidecar byte planes is only grounded for bundle versions >= 0x{:04x}.",
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION
),
],
warnings,
}
}
fn build_save_load_summary(
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
runtime_trailer_block: Option<&SmpRuntimeTrailerBlock>,
rt3_105_post_span_bridge_probe: Option<&SmpRt3105PostSpanBridgeProbe>,
classic_rehydrate_profile_probe: Option<&SmpClassicRehydrateProfileProbe>,
rt3_105_packed_profile_probe: Option<&SmpRt3105PackedProfileProbe>,
rt3_105_save_name_table_probe: Option<&SmpRt3105SaveNameTableProbe>,
) -> Option<SmpSaveLoadSummary> {
let file_extension_hint = file_extension_hint.map(str::to_string);
let container_profile_family = container_profile.map(|profile| profile.profile_family.clone());
let trailer_family = runtime_trailer_block.map(|trailer| trailer.trailer_family.clone());
let bridge_family = rt3_105_post_span_bridge_probe.map(|bridge| bridge.bridge_family.clone());
let candidate_table =
rt3_105_save_name_table_probe.map(|probe| SmpSaveLoadCandidateTableSummary {
source_kind: probe.source_kind.clone(),
semantic_family: probe.semantic_family.clone(),
observed_entry_count: probe.observed_entry_count,
zero_availability_count: probe.zero_trailer_entry_count,
zero_availability_names: probe.zero_trailer_entry_names.clone(),
footer_progress_hex_words: vec![
probe.footer_progress_word_0_hex.clone(),
probe.footer_progress_word_1_hex.clone(),
],
});
if let Some(probe) = classic_rehydrate_profile_probe {
let block = &probe.packed_profile_block;
let mut notes = vec![
"Classic save load reaches the grounded late rehydrate band 0x32dc -> 0x3714 -> 0x3715."
.to_string(),
"The file exposes one exact 0x108 packed-profile block between progress ids 0x3714 and 0x3715."
.to_string(),
];
if let Some(map_path) = &block.map_path {
notes.push(format!("Packed profile map path: {map_path}"));
}
if let Some(display_name) = &block.display_name {
notes.push(format!("Packed profile display name: {display_name}"));
}
return Some(SmpSaveLoadSummary {
file_extension_hint,
container_profile_family,
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
packed_profile_kind: Some("classic-rehydrate-profile".to_string()),
packed_profile_family: Some(probe.profile_family.clone()),
packed_profile_offset: Some(probe.packed_profile_offset),
packed_profile_len: Some(probe.packed_profile_len),
map_path: block.map_path.clone(),
display_name: block.display_name.clone(),
profile_byte_0x77: Some(block.profile_byte_0x77),
profile_byte_0x77_hex: Some(block.profile_byte_0x77_hex.clone()),
profile_byte_0x82: Some(block.profile_byte_0x82),
profile_byte_0x82_hex: Some(block.profile_byte_0x82_hex.clone()),
profile_byte_0x97: Some(block.profile_byte_0x97),
profile_byte_0x97_hex: Some(block.profile_byte_0x97_hex.clone()),
profile_byte_0xc5: Some(block.profile_byte_0xc5),
profile_byte_0xc5_hex: Some(block.profile_byte_0xc5_hex.clone()),
trailer_family,
bridge_family: None,
candidate_table,
notes,
});
}
if let Some(probe) = rt3_105_packed_profile_probe {
let block = &probe.packed_profile_block;
let mechanism_family = rt3_105_post_span_bridge_probe
.map(|bridge| bridge.bridge_family.clone())
.unwrap_or_else(|| match probe.profile_family.as_str() {
"rt3-105-scenario-save-container-v1" => {
"rt3-105-scenario-save-profile-analog-v1".to_string()
}
"rt3-105-alt-save-container-v1" => "rt3-105-alt-save-profile-analog-v1".to_string(),
_ => "rt3-105-save-profile-analog-v1".to_string(),
});
let mechanism_confidence = if rt3_105_post_span_bridge_probe.is_some() {
"mixed"
} else {
"inferred"
}
.to_string();
let mut notes = Vec::new();
if let Some(bridge) = rt3_105_post_span_bridge_probe {
notes.push(format!(
"RT3 1.05 save branch uses {} with selector/descriptor {} -> {}.",
bridge.bridge_family, bridge.selector_high_hex, bridge.descriptor_high_hex
));
} else {
notes.push(
"RT3 1.05 save exposes a packed-profile analogue, but the upstream load bridge is not resolved for this branch."
.to_string(),
);
}
if let Some(map_path) = &block.map_path {
notes.push(format!("Packed profile map path: {map_path}"));
}
if let Some(display_name) = &block.display_name {
notes.push(format!("Packed profile display name: {display_name}"));
}
if let Some(table) = &candidate_table {
notes.push(format!(
"Candidate table source {} carries {} entries with {} zero-availability overrides.",
table.source_kind, table.observed_entry_count, table.zero_availability_count
));
}
return Some(SmpSaveLoadSummary {
file_extension_hint,
container_profile_family,
mechanism_family,
mechanism_confidence,
packed_profile_kind: Some("rt3-105-packed-profile".to_string()),
packed_profile_family: Some(probe.profile_family.clone()),
packed_profile_offset: Some(probe.packed_profile_offset),
packed_profile_len: Some(probe.packed_profile_len),
map_path: block.map_path.clone(),
display_name: block.display_name.clone(),
profile_byte_0x77: Some(block.profile_byte_0x77),
profile_byte_0x77_hex: Some(block.profile_byte_0x77_hex.clone()),
profile_byte_0x82: Some(block.profile_byte_0x82),
profile_byte_0x82_hex: Some(block.profile_byte_0x82_hex.clone()),
profile_byte_0x97: Some(block.profile_byte_0x97),
profile_byte_0x97_hex: Some(block.profile_byte_0x97_hex.clone()),
profile_byte_0xc5: Some(block.profile_byte_0xc5),
profile_byte_0xc5_hex: Some(block.profile_byte_0xc5_hex.clone()),
trailer_family,
bridge_family,
candidate_table,
notes,
});
}
if let Some(table) = candidate_table {
return Some(SmpSaveLoadSummary {
file_extension_hint,
container_profile_family,
mechanism_family: "rt3-105-candidate-catalog-source-v1".to_string(),
mechanism_confidence: "mixed".to_string(),
packed_profile_kind: None,
packed_profile_family: None,
packed_profile_offset: None,
packed_profile_len: None,
map_path: None,
display_name: None,
profile_byte_0x77: None,
profile_byte_0x77_hex: None,
profile_byte_0x82: None,
profile_byte_0x82_hex: None,
profile_byte_0x97: None,
profile_byte_0x97_hex: None,
profile_byte_0xc5: None,
profile_byte_0xc5_hex: None,
trailer_family,
bridge_family,
notes: vec![
format!(
"The file carries the shared 1.05 candidate table source block through {}.",
table.source_kind
),
format!(
"The table exposes {} named entries with {} zero-availability overrides.",
table.observed_entry_count, table.zero_availability_count
),
],
candidate_table: Some(table),
});
}
None
}
fn parse_preamble(bytes: &[u8]) -> SmpPreamble {
let byte_len = bytes.len().min(PREAMBLE_U32_WORD_COUNT * 4);
let words = bytes[..byte_len]
.chunks_exact(4)
.enumerate()
.map(|(index, chunk)| {
let value_le = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
SmpPreambleWord {
index,
offset: index * 4,
value_le,
value_hex: format!("0x{value_le:08x}"),
}
})
.collect::<Vec<_>>();
SmpPreamble {
byte_len,
word_count: words.len(),
words,
}
}
fn parse_shared_header(bytes: &[u8]) -> Option<SmpSharedHeader> {
let words = read_preamble_words(bytes)?;
let shared_signature_words_1_to_7 = words[1..=7].to_vec();
let payload_window_words_8_to_9 = words[8..=9].to_vec();
let reserved_words_10_to_14 = words[10..=14].to_vec();
let final_flag_word = words[15];
Some(SmpSharedHeader {
byte_len: PREAMBLE_U32_WORD_COUNT * 4,
root_kind_word: words[0],
root_kind_word_hex: format!("0x{:08x}", words[0]),
primary_family_tag: words[1],
primary_family_tag_hex: format!("0x{:08x}", words[1]),
shared_signature_hex_words_1_to_7: shared_signature_words_1_to_7
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
matches_grounded_common_signature: shared_signature_words_1_to_7
== SHARED_SIGNATURE_WORDS_1_TO_7,
shared_signature_words_1_to_7,
payload_window_hex_words_8_to_9: payload_window_words_8_to_9
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
payload_window_words_8_to_9,
reserved_words_10_to_14_all_zero: reserved_words_10_to_14.iter().all(|word| *word == 0),
reserved_words_10_to_14,
final_flag_word,
final_flag_word_hex: format!("0x{final_flag_word:08x}"),
})
}
fn classify_header_variant_probe(shared_header: &SmpSharedHeader) -> SmpHeaderVariantProbe {
let words = &shared_header.shared_signature_words_1_to_7;
let root = shared_header.root_kind_word;
let final_flag = shared_header.final_flag_word;
let (variant_family, evidence, is_known_family) = match (root, words.as_slice(), final_flag) {
(
0x00002649,
[
0x00002ee0,
0x00040001,
0x00028000,
0x00010000,
0x00000771,
0x00000771,
0x00000771,
],
0x00000001,
) => (
"rt3-105-gmx-header-v1".to_string(),
vec![
"root kind word 0x00002649".to_string(),
"1.05 common signature words 1..7".to_string(),
"final flag 0x00000001".to_string(),
],
true,
),
(
0x000025e5,
[
0x00002ee0,
0x00040001,
0x00028000,
0x00010000,
0x00000771,
0x00000771,
0x00000771,
],
0x00000000,
) => (
"rt3-105-common-header-v1".to_string(),
vec![
"root kind word 0x000025e5".to_string(),
"1.05 common signature words 1..7".to_string(),
"final flag 0x00000000".to_string(),
],
true,
),
(
0x000025e5,
[
0x00002ee0,
0x00040001,
0x00018000,
0x00010000,
0x00000746,
0x00000746,
0x00000746,
],
0x00000000,
) => (
"rt3-105-scenario-save-header-v1".to_string(),
vec![
"root kind word 0x000025e5".to_string(),
"1.05 scenario-save signature words 1..7".to_string(),
"final flag 0x00000000".to_string(),
],
true,
),
(
0x000025e5,
[
0x00002ee0,
0x0001c001,
0x00018000,
0x00010000,
0x00000754,
0x00000754,
0x00000754,
],
0x00000000,
) => (
"rt3-105-alt-save-header-v1".to_string(),
vec![
"root kind word 0x000025e5".to_string(),
"1.05 alternate-save signature words 1..7".to_string(),
"final flag 0x00000000".to_string(),
],
true,
),
(
0x000026ad,
[
0x00002ee0,
0x00014001,
0x00020000,
0x00010000,
0x00000725,
0x00000725,
0x00000725,
],
0x00000100,
) => (
"rt3-classic-gms-header-v1".to_string(),
vec![
"root kind word 0x000026ad".to_string(),
"classic save signature words 1..7".to_string(),
"final flag 0x00000100".to_string(),
],
true,
),
(
0x000026ad,
[
0x00002ee0,
0x0001c001,
0x00018000,
0x00010000,
0x00000765,
0x00000765,
0x00000765,
],
0x00000001,
) => (
"rt3-classic-gmx-header-v1".to_string(),
vec![
"root kind word 0x000026ad".to_string(),
"classic sandbox signature words 1..7".to_string(),
"final flag 0x00000001".to_string(),
],
true,
),
(0x000025e5, [0x00002ee0, _, _, 0x00010000, _, _, _], 0x00000000 | 0x00000100) => (
"rt3-map-header-family".to_string(),
vec![
"root kind word 0x000025e5".to_string(),
"map-family anchor 0x00002ee0".to_string(),
"word4 0x00010000".to_string(),
],
true,
),
_ => (
"unknown".to_string(),
vec![format!(
"root=0x{root:08x}, words1..7={}, final=0x{final_flag:08x}",
words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect::<Vec<_>>()
.join(", ")
)],
false,
),
};
SmpHeaderVariantProbe {
variant_family,
variant_evidence: evidence,
is_known_family,
}
}
fn read_preamble_words(bytes: &[u8]) -> Option<[u32; PREAMBLE_U32_WORD_COUNT]> {
if bytes.len() < PREAMBLE_U32_WORD_COUNT * 4 {
return None;
}
let mut words = [0u32; PREAMBLE_U32_WORD_COUNT];
for (index, chunk) in bytes[..PREAMBLE_U32_WORD_COUNT * 4]
.chunks_exact(4)
.enumerate()
{
words[index] = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
}
Some(words)
}
fn probe_early_content_layout(
bytes: &[u8],
ascii_run: &SmpAsciiPreview,
) -> Option<SmpEarlyContentProbe> {
let search_start = ascii_run.offset + ascii_run.byte_len;
let first_post_text_nonzero_offset = find_next_nonzero_offset(bytes, search_start)?;
let zero_pad_after_text_len = first_post_text_nonzero_offset.saturating_sub(search_start);
let first_zero_run_after_block = find_zero_run(
bytes,
first_post_text_nonzero_offset,
EARLY_ZERO_RUN_THRESHOLD,
)
.unwrap_or(bytes.len());
let first_post_text_block = &bytes[first_post_text_nonzero_offset..first_zero_run_after_block];
let secondary_nonzero_offset = find_next_nonzero_offset(bytes, first_zero_run_after_block);
let trailing_zero_pad_after_first_block_len = secondary_nonzero_offset
.map(|offset| offset.saturating_sub(first_zero_run_after_block))
.unwrap_or_else(|| bytes.len().saturating_sub(first_zero_run_after_block));
let secondary_aligned_word_window_offset = secondary_nonzero_offset.map(|offset| offset & !0x3);
let secondary_aligned_word_window_words = secondary_aligned_word_window_offset
.map(|offset| read_u32_window(bytes, offset, EARLY_ALIGNED_WORD_WINDOW_COUNT))
.unwrap_or_default();
let secondary_preview_hex = secondary_nonzero_offset
.map(|offset| {
hex_encode(&bytes[offset..bytes.len().min(offset + EARLY_PREVIEW_BYTE_LIMIT)])
})
.unwrap_or_default();
Some(SmpEarlyContentProbe {
first_post_text_nonzero_offset,
zero_pad_after_text_len,
first_post_text_block_len: first_post_text_block.len(),
first_post_text_block_hex: hex_encode(first_post_text_block),
trailing_zero_pad_after_first_block_len,
secondary_nonzero_offset,
secondary_aligned_word_window_offset,
secondary_aligned_word_window_hex_words: secondary_aligned_word_window_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
secondary_aligned_word_window_words,
secondary_preview_hex,
})
}
fn classify_secondary_variant_probe(
probe: &SmpEarlyContentProbe,
) -> Option<SmpSecondaryVariantProbe> {
let aligned_window_offset = probe.secondary_aligned_word_window_offset?;
let words = probe.secondary_aligned_word_window_words.clone();
if words.is_empty() {
return None;
}
let mut evidence = Vec::new();
let variant_family = match words.as_slice() {
[0x001e0000, 0x86a00100, 0x03000001, 0xf0000100, ..] => {
evidence.push("leading word 0x001e0000".to_string());
evidence.push("anchor word 0x86a00100".to_string());
evidence.push("third/fourth words 0x03000001 and 0xf0000100".to_string());
"rt3-gms-family-v1".to_string()
}
[0x000a0000, 0x49f00100, 0x00000002, 0xa0000000, ..] => {
evidence.push("leading word 0x000a0000".to_string());
evidence.push("anchor word 0x49f00100".to_string());
evidence.push("third/fourth words 0x00000002 and 0xa0000000".to_string());
"rt3-gmx-family-v1".to_string()
}
[0x001c0000, 0x86a00100, 0x00000001, 0xa0000000, ..] => {
evidence.push("leading word 0x001c0000".to_string());
evidence.push("anchor word 0x86a00100".to_string());
evidence.push("third/fourth words 0x00000001 and 0xa0000000".to_string());
"rt3-105-gms-family-v1".to_string()
}
[0x00190000, 0x86a00100, 0x00000001, 0xa0000000, ..] => {
evidence.push("leading word 0x00190000".to_string());
evidence.push("anchor word 0x86a00100".to_string());
evidence.push("third/fourth words 0x00000001 and 0xa0000000".to_string());
"rt3-105-gmx-family-v1".to_string()
}
[0x00130000, 0x86a00100, 0x21000001, 0xa0000100, ..] => {
evidence.push("leading word 0x00130000".to_string());
evidence.push("anchor word 0x86a00100".to_string());
evidence.push("third/fourth words 0x21000001 and 0xa0000100".to_string());
"rt3-105-gms-scenario-family-v1".to_string()
}
[0x00010000, 0x49f00100, 0x00000002, 0xa0000000, ..] => {
evidence.push("leading word 0x00010000".to_string());
evidence.push("anchor word 0x49f00100".to_string());
evidence.push("third/fourth words 0x00000002 and 0xa0000000".to_string());
"rt3-105-gms-alt-family-v1".to_string()
}
[0x86a00100, 0x00000001, 0xa0000000, 0x00000186, ..] => {
evidence.push("window starts directly on 0x86a00100".to_string());
evidence.push("likely same family with missing leading unaligned word".to_string());
"rt3-family-unaligned-anchor".to_string()
}
_ => {
evidence.push(format!(
"unrecognized leading words: {}",
words
.iter()
.take(4)
.map(|word| format!("0x{word:08x}"))
.collect::<Vec<_>>()
.join(", ")
));
"unknown".to_string()
}
};
Some(SmpSecondaryVariantProbe {
aligned_window_offset,
hex_words: words.iter().map(|word| format!("0x{word:08x}")).collect(),
words,
variant_family,
variant_evidence: evidence,
})
}
fn classify_container_profile(
file_extension_hint: Option<&str>,
header_variant_probe: Option<&SmpHeaderVariantProbe>,
secondary_variant_probe: Option<&SmpSecondaryVariantProbe>,
) -> Option<SmpContainerProfile> {
let header_family = header_variant_probe.map(|probe| probe.variant_family.as_str())?;
let secondary_family = secondary_variant_probe.map(|probe| probe.variant_family.as_str())?;
let extension = file_extension_hint.unwrap_or("");
let (profile_family, profile_evidence, is_known_profile) =
match (extension, header_family, secondary_family) {
("gms", "rt3-classic-gms-header-v1", "rt3-gms-family-v1") => (
"rt3-classic-save-container-v1".to_string(),
vec![
"extension .gms".to_string(),
"classic save header family".to_string(),
"classic save secondary window family".to_string(),
],
true,
),
("gmx", "rt3-classic-gmx-header-v1", "rt3-gmx-family-v1") => (
"rt3-classic-sandbox-container-v1".to_string(),
vec![
"extension .gmx".to_string(),
"classic sandbox header family".to_string(),
"classic sandbox secondary window family".to_string(),
],
true,
),
("gms", "rt3-105-common-header-v1", "rt3-105-gms-family-v1") => (
"rt3-105-save-container-v1".to_string(),
vec![
"extension .gms".to_string(),
"1.05 common header family".to_string(),
"1.05 save secondary window family".to_string(),
],
true,
),
("gms", "rt3-105-scenario-save-header-v1", "rt3-105-gms-scenario-family-v1") => (
"rt3-105-scenario-save-container-v1".to_string(),
vec![
"extension .gms".to_string(),
"1.05 scenario-save header family".to_string(),
"1.05 scenario-save secondary window family".to_string(),
],
true,
),
("gms", "rt3-105-alt-save-header-v1", "rt3-105-gms-alt-family-v1") => (
"rt3-105-alt-save-container-v1".to_string(),
vec![
"extension .gms".to_string(),
"1.05 alternate-save header family".to_string(),
"1.05 alternate-save secondary window family".to_string(),
],
true,
),
("gmx", "rt3-105-gmx-header-v1", "rt3-105-gmx-family-v1") => (
"rt3-105-sandbox-container-v1".to_string(),
vec![
"extension .gmx".to_string(),
"1.05 sandbox header family".to_string(),
"1.05 sandbox secondary window family".to_string(),
],
true,
),
("gmp", "rt3-105-common-header-v1", "rt3-family-unaligned-anchor") => (
"rt3-105-map-container-v1".to_string(),
vec![
"extension .gmp".to_string(),
"1.05 common header family".to_string(),
"map-style secondary unaligned anchor".to_string(),
],
true,
),
("gmp", "rt3-105-scenario-save-header-v1", "unknown") => (
"rt3-105-scenario-map-container-v1".to_string(),
vec![
"extension .gmp".to_string(),
"1.05 scenario-map header family".to_string(),
"fixed candidate-availability table range present despite unknown early secondary window".to_string(),
],
true,
),
("gmp", "rt3-105-alt-save-header-v1", "unknown") => (
"rt3-105-alt-map-container-v1".to_string(),
vec![
"extension .gmp".to_string(),
"1.05 alternate-map header family".to_string(),
"fixed candidate-availability table range present despite unknown early secondary window".to_string(),
],
true,
),
("gmp", "rt3-map-header-family", "rt3-family-unaligned-anchor") => (
"rt3-map-container-family".to_string(),
vec![
"extension .gmp".to_string(),
"map header family".to_string(),
"map-style secondary unaligned anchor".to_string(),
],
true,
),
(_, header_family, secondary_family) => (
"unknown".to_string(),
vec![
format!(
"extension {}",
if extension.is_empty() {
"<none>"
} else {
extension
}
),
format!("header family {header_family}"),
format!("secondary family {secondary_family}"),
],
false,
),
};
Some(SmpContainerProfile {
profile_family,
profile_evidence,
is_known_profile,
})
}
fn parse_save_bootstrap_block(
container_profile: Option<&SmpContainerProfile>,
secondary_variant_probe: Option<&SmpSecondaryVariantProbe>,
) -> Option<SmpSaveBootstrapBlock> {
let profile = container_profile?;
let secondary = secondary_variant_probe?;
let words = &secondary.words;
if words.len() < 8 {
return None;
}
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
Some(SmpSaveBootstrapBlock {
profile_family: profile.profile_family.clone(),
aligned_window_offset: secondary.aligned_window_offset,
leading_word: words[0],
leading_word_hex: format!("0x{:08x}", words[0]),
anchor_word: words[1],
anchor_word_hex: format!("0x{:08x}", words[1]),
descriptor_word_2: words[2],
descriptor_word_2_hex: format!("0x{:08x}", words[2]),
descriptor_word_3: words[3],
descriptor_word_3_hex: format!("0x{:08x}", words[3]),
descriptor_word_4: words[4],
descriptor_word_4_hex: format!("0x{:08x}", words[4]),
descriptor_word_5: words[5],
descriptor_word_5_hex: format!("0x{:08x}", words[5]),
descriptor_word_6: words[6],
descriptor_word_6_hex: format!("0x{:08x}", words[6]),
descriptor_word_7: words[7],
descriptor_word_7_hex: format!("0x{:08x}", words[7]),
})
}
fn parse_runtime_anchor_cycle_block(
bytes: &[u8],
container_profile: Option<&SmpContainerProfile>,
secondary_variant_probe: Option<&SmpSecondaryVariantProbe>,
) -> Option<SmpRuntimeAnchorCycleBlock> {
let profile = container_profile?;
let secondary = secondary_variant_probe?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-classic-sandbox-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
| "rt3-105-sandbox-container-v1"
);
if !supported {
return None;
}
let cycle_start_offset = secondary.aligned_window_offset + 0x1c;
let cycle_words = read_u32_window(bytes, cycle_start_offset, 9);
if cycle_words.len() < 9 {
return None;
}
let mut full_cycle_count = 0usize;
let mut cursor = cycle_start_offset;
while read_u32_window(bytes, cursor, cycle_words.len()) == cycle_words {
full_cycle_count += 1;
cursor += cycle_words.len() * 4;
}
if full_cycle_count == 0 {
return None;
}
let mut partial_cycle_word_count = 0usize;
while partial_cycle_word_count < cycle_words.len() {
let offset = cursor + partial_cycle_word_count * 4;
if read_u32_at(bytes, offset) == Some(cycle_words[partial_cycle_word_count]) {
partial_cycle_word_count += 1;
} else {
break;
}
}
let trailer_offset = cursor + partial_cycle_word_count * 4;
let trailer_words = read_u32_window(bytes, trailer_offset, 16);
Some(SmpRuntimeAnchorCycleBlock {
profile_family: profile.profile_family.clone(),
cycle_start_offset,
cycle_hex_words: cycle_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
cycle_words,
full_cycle_count,
partial_cycle_word_count,
trailer_offset,
trailer_hex_words: trailer_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
trailer_words,
})
}
fn parse_save_anchor_run_block(
bytes: &[u8],
container_profile: Option<&SmpContainerProfile>,
save_bootstrap_block: Option<&SmpSaveBootstrapBlock>,
) -> Option<SmpSaveAnchorRunBlock> {
let profile = container_profile?;
let bootstrap = save_bootstrap_block?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
let cycle_start_offset = bootstrap.aligned_window_offset + 0x1c;
let cycle_words = read_u32_window(bytes, cycle_start_offset, 9);
if cycle_words.len() < 9 {
return None;
}
let mut full_cycle_count = 0usize;
let mut cursor = cycle_start_offset;
while read_u32_window(bytes, cursor, cycle_words.len()) == cycle_words {
full_cycle_count += 1;
cursor += cycle_words.len() * 4;
}
if full_cycle_count == 0 {
return None;
}
let mut partial_cycle_word_count = 0usize;
while partial_cycle_word_count < cycle_words.len() {
let offset = cursor + partial_cycle_word_count * 4;
if read_u32_at(bytes, offset) == Some(cycle_words[partial_cycle_word_count]) {
partial_cycle_word_count += 1;
} else {
break;
}
}
let trailer_offset = cursor + partial_cycle_word_count * 4;
let trailer_words = read_u32_window(bytes, trailer_offset, 12);
Some(SmpSaveAnchorRunBlock {
profile_family: profile.profile_family.clone(),
cycle_start_offset,
cycle_hex_words: cycle_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
cycle_words,
full_cycle_count,
partial_cycle_word_count,
trailer_offset,
trailer_hex_words: trailer_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
trailer_words,
})
}
fn parse_runtime_trailer_block(
container_profile: Option<&SmpContainerProfile>,
runtime_anchor_cycle_block: Option<&SmpRuntimeAnchorCycleBlock>,
) -> Option<SmpRuntimeTrailerBlock> {
let profile = container_profile?;
let anchor = runtime_anchor_cycle_block?;
let words = &anchor.trailer_words;
if words.len() < 16 {
return None;
}
let trailer_family = match profile.profile_family.as_str() {
"rt3-classic-save-container-v1"
if words[..6]
== [
0x00020000, 0x00030000, 0x00010000, 0x00010000, 0x00010000, 0x00020000,
] =>
{
"rt3-classic-save-trailer-v1"
}
"rt3-classic-sandbox-container-v1"
if words[..6]
== [
0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00000000, 0x00000000,
] =>
{
"rt3-classic-sandbox-trailer-v1"
}
"rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
if words[..6]
== [
0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00000000, 0x00000000,
] =>
{
"rt3-105-save-trailer-v1"
}
"rt3-105-sandbox-container-v1"
if words[..6]
== [
0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00000000, 0x00000000,
] =>
{
"rt3-105-sandbox-trailer-v1"
}
_ => "unknown",
}
.to_string();
let tag_chunk_id_u16 = (words[6] >> 16) as u16;
let length_high_u16 = (words[7] >> 16) as u16;
let selector_high_u16 = (words[8] >> 16) as u16;
let descriptor_high_u16 = (words[10] >> 16) as u16;
let tag_chunk_id_grounded_alignment =
classify_runtime_trailer_chunk_id_grounded_alignment(tag_chunk_id_u16).map(str::to_string);
let mut trailer_evidence = vec![
format!("container profile {}", profile.profile_family),
format!(
"prefix words {}",
words[..6]
.iter()
.map(|word| format!("0x{word:08x}"))
.collect::<Vec<_>>()
.join(", ")
),
format!("high-16 chunk id 0x{tag_chunk_id_u16:04x} from trailer word 6"),
format!("high-16 span 0x{length_high_u16:04x} from trailer word 7"),
format!("high-16 selector 0x{selector_high_u16:04x} from trailer word 8"),
format!("high-16 descriptor 0x{descriptor_high_u16:04x} from trailer word 10"),
];
if let Some(alignment) = &tag_chunk_id_grounded_alignment {
trailer_evidence.push(alignment.clone());
}
Some(SmpRuntimeTrailerBlock {
profile_family: profile.profile_family.clone(),
trailer_family,
trailer_evidence,
trailer_offset: anchor.trailer_offset,
prefix_words_0_to_5: words[..6].to_vec(),
prefix_hex_words_0_to_5: words[..6]
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
tag_word_6: words[6],
tag_word_6_hex: format!("0x{:08x}", words[6]),
tag_chunk_id_u16,
tag_chunk_id_hex: format!("0x{tag_chunk_id_u16:04x}"),
tag_chunk_id_grounded_alignment,
length_word_7: words[7],
length_word_7_hex: format!("0x{:08x}", words[7]),
length_high_u16,
length_high_hex: format!("0x{length_high_u16:04x}"),
selector_word_8: words[8],
selector_word_8_hex: format!("0x{:08x}", words[8]),
selector_high_u16,
selector_high_hex: format!("0x{selector_high_u16:04x}"),
layout_word_9: words[9],
layout_word_9_hex: format!("0x{:08x}", words[9]),
descriptor_word_10: words[10],
descriptor_word_10_hex: format!("0x{:08x}", words[10]),
descriptor_high_u16,
descriptor_high_hex: format!("0x{descriptor_high_u16:04x}"),
descriptor_word_11: words[11],
descriptor_word_11_hex: format!("0x{:08x}", words[11]),
counter_word_12: words[12],
counter_word_12_hex: format!("0x{:08x}", words[12]),
offset_word_13: words[13],
offset_word_13_hex: format!("0x{:08x}", words[13]),
span_word_14: words[14],
span_word_14_hex: format!("0x{:08x}", words[14]),
mode_word_15: words[15],
mode_word_15_hex: format!("0x{:08x}", words[15]),
words: words.to_vec(),
hex_words: words.iter().map(|word| format!("0x{word:08x}")).collect(),
})
}
fn classify_runtime_trailer_chunk_id_grounded_alignment(
tag_chunk_id_u16: u16,
) -> Option<&'static str> {
match tag_chunk_id_u16 {
0x2ee1 => Some(
"High-16 chunk id 0x2ee1 matches the disassembly-grounded map-style bundle family already read by shell_setup_load_selected_profile_bundle_into_payload_record.",
),
_ => None,
}
}
fn parse_runtime_post_span_probe(
bytes: &[u8],
runtime_trailer_block: Option<&SmpRuntimeTrailerBlock>,
) -> Option<SmpRuntimePostSpanProbe> {
let trailer = runtime_trailer_block?;
let span_target_offset = trailer.trailer_offset + trailer.length_high_u16 as usize;
let next_nonzero_offset = find_next_nonzero_offset(bytes, span_target_offset);
let header_candidates =
collect_runtime_post_span_header_candidates(bytes, span_target_offset, 0x8000);
let next_aligned_candidate_offset = header_candidates.first().map(|candidate| candidate.offset);
let next_aligned_candidate_words = header_candidates
.first()
.map(|candidate| candidate.words.clone())
.unwrap_or_default();
let grounded_progress_hits =
find_grounded_progress_high16_hits(bytes, span_target_offset, 0x8000);
Some(SmpRuntimePostSpanProbe {
profile_family: trailer.profile_family.clone(),
span_target_offset,
next_nonzero_offset,
next_aligned_candidate_offset,
next_aligned_candidate_hex_words: next_aligned_candidate_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
next_aligned_candidate_words,
header_candidates,
grounded_progress_hits,
})
}
fn parse_classic_rehydrate_profile_probe(
bytes: &[u8],
runtime_post_span_probe: Option<&SmpRuntimePostSpanProbe>,
) -> Option<SmpClassicRehydrateProfileProbe> {
let post_span = runtime_post_span_probe?;
if post_span.profile_family != "rt3-classic-save-container-v1" {
return None;
}
let progress_32dc_offset =
parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x32dc)?;
let progress_3714_offset =
parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x3714)?;
let progress_3715_offset =
parse_grounded_progress_hit_offset(&post_span.grounded_progress_hits, 0x3715)?;
let packed_profile_offset = progress_3714_offset + 4;
let packed_profile_len = progress_3715_offset.checked_sub(packed_profile_offset)?;
if packed_profile_len != 0x108 {
return None;
}
let ascii_runs =
collect_ascii_previews_in_range(bytes, packed_profile_offset, progress_3715_offset, 4);
let packed_profile_block =
parse_classic_packed_profile_block(bytes, packed_profile_offset, packed_profile_len)?;
Some(SmpClassicRehydrateProfileProbe {
profile_family: post_span.profile_family.clone(),
progress_32dc_offset,
progress_3714_offset,
progress_3715_offset,
packed_profile_offset,
packed_profile_len,
packed_profile_len_hex: format!("0x{packed_profile_len:03x}"),
packed_profile_block,
ascii_runs,
})
}
fn parse_classic_packed_profile_block(
bytes: &[u8],
packed_profile_offset: usize,
packed_profile_len: usize,
) -> Option<SmpClassicPackedProfileBlock> {
let block_end = packed_profile_offset.checked_add(packed_profile_len)?;
if block_end > bytes.len() || packed_profile_len != 0x108 {
return None;
}
let leading_word_0 = read_u32_at(bytes, packed_profile_offset)?;
let trailing_zero_word_count_after_leading_word = (1..4)
.take_while(|index| {
read_u32_at(bytes, packed_profile_offset + (index * 4)).is_some_and(|word| word == 0)
})
.count();
let map_path_offset = 0x13;
let display_name_offset = 0x46;
let stable_nonzero_word_offsets = [0x00usize, 0x10, 0x78, 0x7c, 0x84, 0x88];
let stable_nonzero_words = stable_nonzero_word_offsets
.iter()
.filter_map(|relative_offset| {
let value = read_u32_at(bytes, packed_profile_offset + relative_offset)?;
if value == 0 {
return None;
}
Some(SmpPackedProfileWordLane {
relative_offset: *relative_offset,
relative_offset_hex: format!("0x{relative_offset:02x}"),
value,
value_hex: format!("0x{value:08x}"),
})
})
.collect::<Vec<_>>();
Some(SmpClassicPackedProfileBlock {
relative_len: packed_profile_len,
relative_len_hex: format!("0x{packed_profile_len:03x}"),
leading_word_0,
leading_word_0_hex: format!("0x{leading_word_0:08x}"),
trailing_zero_word_count_after_leading_word,
map_path_offset,
map_path: read_c_string_in_range(bytes, packed_profile_offset + map_path_offset, block_end),
display_name_offset,
display_name: read_c_string_in_range(
bytes,
packed_profile_offset + display_name_offset,
block_end,
),
profile_byte_0x77: bytes[packed_profile_offset + 0x77],
profile_byte_0x77_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x77]),
profile_byte_0x82: bytes[packed_profile_offset + 0x82],
profile_byte_0x82_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x82]),
profile_byte_0x97: bytes[packed_profile_offset + 0x97],
profile_byte_0x97_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x97]),
profile_byte_0xc5: bytes[packed_profile_offset + 0xc5],
profile_byte_0xc5_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0xc5]),
stable_nonzero_words,
})
}
fn parse_rt3_105_packed_profile_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
header_variant_probe: Option<&SmpHeaderVariantProbe>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpRt3105PackedProfileProbe> {
let profile_family = if container_profile.is_some_and(|profile| {
matches!(
profile.profile_family.as_str(),
"rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
)
}) {
container_profile
.expect("checked above")
.profile_family
.clone()
} else if file_extension_hint == Some("gms")
&& header_variant_probe.is_some_and(|probe| {
matches!(
probe.variant_family.as_str(),
"rt3-105-common-header-v1"
| "rt3-105-scenario-save-header-v1"
| "rt3-105-alt-save-header-v1"
| "rt3-map-header-family"
)
})
{
"rt3-105-save-analog-block-inferred".to_string()
} else {
return None;
};
if file_extension_hint != Some("gms") {
return None;
}
let map_path_offset = find_c_string_with_suffix_in_range(bytes, 0x7000, 0x9000, ".gmp")?;
let packed_profile_offset = map_path_offset.checked_sub(0x10)?;
let packed_profile_len = 0x108usize;
let block_end = packed_profile_offset.checked_add(packed_profile_len)?;
if block_end > bytes.len() {
return None;
}
let packed_profile_block =
parse_rt3_105_packed_profile_block(bytes, packed_profile_offset, packed_profile_len)?;
let ascii_runs = collect_ascii_previews_in_range(bytes, packed_profile_offset, block_end, 4);
Some(SmpRt3105PackedProfileProbe {
profile_family,
packed_profile_offset,
packed_profile_len,
packed_profile_len_hex: format!("0x{packed_profile_len:03x}"),
packed_profile_block,
ascii_runs,
})
}
fn parse_rt3_105_post_span_bridge_probe(
runtime_trailer_block: Option<&SmpRuntimeTrailerBlock>,
runtime_post_span_probe: Option<&SmpRuntimePostSpanProbe>,
rt3_105_packed_profile_probe: Option<&SmpRt3105PackedProfileProbe>,
) -> Option<SmpRt3105PostSpanBridgeProbe> {
let trailer = runtime_trailer_block?;
let post_span = runtime_post_span_probe?;
let packed_profile = rt3_105_packed_profile_probe?;
let supported = matches!(
trailer.profile_family.as_str(),
"rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
| "rt3-105-save-analog-block-inferred"
);
if !supported || trailer.profile_family != post_span.profile_family {
return None;
}
let next_candidate_high_u16_words = post_span
.header_candidates
.first()
.map(|candidate| candidate.high_u16_words.clone())
.unwrap_or_default();
let next_candidate_high_hex_words = next_candidate_high_u16_words
.iter()
.map(|word| format!("0x{word:04x}"))
.collect::<Vec<_>>();
let next_candidate_offset = post_span.next_aligned_candidate_offset;
let next_candidate_delta_from_span_target =
next_candidate_offset.and_then(|offset| offset.checked_sub(post_span.span_target_offset));
let packed_profile_delta_from_span_target = packed_profile
.packed_profile_offset
.checked_sub(post_span.span_target_offset)?;
let next_candidate_delta_from_packed_profile = next_candidate_offset
.map(|offset| offset as i64 - packed_profile.packed_profile_offset as i64);
let mut bridge_evidence = vec![
format!("profile family {}", trailer.profile_family),
format!("selector high {}", trailer.selector_high_hex),
format!("descriptor high {}", trailer.descriptor_high_hex),
format!(
"packed profile sits +0x{packed_profile_delta_from_span_target:x} from span target"
),
];
if let Some(delta) = next_candidate_delta_from_span_target {
bridge_evidence.push(format!("next candidate sits +0x{delta:x} from span target"));
}
if let Some(delta) = next_candidate_delta_from_packed_profile {
bridge_evidence.push(format!(
"next candidate is {delta:+#x} relative to packed profile"
));
}
let bridge_family = match (
trailer.selector_high_u16,
trailer.descriptor_high_u16,
next_candidate_high_u16_words.as_slice(),
) {
(0x7110, 0x7801 | 0x7401, [0x6200, 0x0000, 0xfff7, 0x5515, ..]) => {
bridge_evidence.push(format!(
"selector/descriptor pair 0x7110 -> 0x{:04x}",
trailer.descriptor_high_u16
));
bridge_evidence.push(
"next candidate begins with high-16 lanes 0x6200/0x0000/0xfff7/0x5515"
.to_string(),
);
"rt3-105-save-post-span-bridge-v1"
}
(0x54cd, 0x5901, [0x1500, 0x0100, 0x4100, 0x0200, ..]) => {
bridge_evidence.push("selector/descriptor pair 0x54cd -> 0x5901".to_string());
bridge_evidence.push(
"next candidate begins with high-16 lanes 0x1500/0x0100/0x4100/0x0200"
.to_string(),
);
"rt3-105-alt-save-post-span-bridge-v1"
}
(0x0001, 0x0186, [0x0186, 0x0006, 0x0006, 0x0001, ..]) => {
bridge_evidence.push("selector/descriptor pair 0x0001 -> 0x0186".to_string());
bridge_evidence.push(
"next candidate remains in the local cycle neighborhood with 0x0186/0x0006/0x0006/0x0001"
.to_string(),
);
"rt3-105-scenario-post-span-bridge-v1"
}
_ => "unknown",
}
.to_string();
Some(SmpRt3105PostSpanBridgeProbe {
profile_family: trailer.profile_family.clone(),
bridge_family,
bridge_evidence,
span_target_offset: post_span.span_target_offset,
next_candidate_offset,
next_candidate_delta_from_span_target,
packed_profile_offset: packed_profile.packed_profile_offset,
packed_profile_delta_from_span_target,
next_candidate_delta_from_packed_profile,
selector_high_u16: trailer.selector_high_u16,
selector_high_hex: trailer.selector_high_hex.clone(),
descriptor_high_u16: trailer.descriptor_high_u16,
descriptor_high_hex: trailer.descriptor_high_hex.clone(),
next_candidate_high_u16_words,
next_candidate_high_hex_words,
})
}
fn parse_rt3_105_save_bridge_payload_probe(
bytes: &[u8],
bridge_probe: Option<&SmpRt3105PostSpanBridgeProbe>,
) -> Option<SmpRt3105SaveBridgePayloadProbe> {
let bridge = bridge_probe?;
if bridge.bridge_family != "rt3-105-save-post-span-bridge-v1" {
return None;
}
let primary_block_offset = bridge.next_candidate_offset?;
let primary_block_word_count = 8usize;
let primary_words = read_u32_window(bytes, primary_block_offset, primary_block_word_count);
if primary_words.len() < primary_block_word_count {
return None;
}
let secondary_block_delta_from_primary = 0x1808usize;
let secondary_block_offset = primary_block_offset + secondary_block_delta_from_primary;
let secondary_block_end_offset = bridge.packed_profile_offset;
let secondary_block_len = secondary_block_end_offset.checked_sub(secondary_block_offset)?;
let secondary_preview_word_count = 32usize;
let secondary_words =
read_u32_window(bytes, secondary_block_offset, secondary_preview_word_count);
if secondary_words.len() < secondary_preview_word_count {
return None;
}
let primary_signature_matches = primary_words
== [
0x62000000, 0x00000000, 0xfff70000, 0x55150000, 0x55550000, 0x00000000, 0xfff70000,
0x54550000,
];
let secondary_prefix_matches = secondary_words.starts_with(&[
0x00050000, 0x00050005, 0xfff70000, 0x54540000, 0x545400f9, 0x00f900f9, 0x00f94008,
0x00001555,
]);
let mut evidence = vec![
"bridge family rt3-105-save-post-span-bridge-v1".to_string(),
format!("primary block offset 0x{primary_block_offset:08x}"),
format!("secondary block offset 0x{secondary_block_offset:08x}"),
format!("secondary block delta from primary 0x{secondary_block_delta_from_primary:x}"),
format!("secondary block end offset 0x{secondary_block_end_offset:08x}"),
format!("secondary block span 0x{secondary_block_len:x} bytes"),
];
if primary_signature_matches {
evidence.push(
"primary 8-word bridge block matches the observed 0x6200/0xfff7/0x5515/0x5555 spine"
.to_string(),
);
}
if secondary_prefix_matches {
evidence.push(
"secondary preview matches the observed 0x0005/0xfff7/0x5454 dense block prefix"
.to_string(),
);
}
Some(SmpRt3105SaveBridgePayloadProbe {
profile_family: bridge.profile_family.clone(),
bridge_family: bridge.bridge_family.clone(),
primary_block_offset,
primary_block_len: primary_block_word_count * 4,
primary_block_len_hex: format!("0x{:02x}", primary_block_word_count * 4),
primary_hex_words: primary_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
primary_words,
secondary_block_offset,
secondary_block_delta_from_primary,
secondary_block_delta_from_primary_hex: format!("0x{secondary_block_delta_from_primary:x}"),
secondary_block_end_offset,
secondary_block_len,
secondary_block_len_hex: format!("0x{secondary_block_len:x}"),
secondary_preview_word_count,
secondary_hex_words: secondary_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
secondary_words,
evidence,
})
}
fn parse_save_world_selection_context_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveWorldSelectionContextProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
for chunk_tag_offset in find_u32_le_offsets(bytes, RT3_SAVE_WORLD_BLOCK_CHUNK_TAG) {
let payload_offset = chunk_tag_offset + 4;
let next_chunk_tag_offset = payload_offset.checked_add(RT3_SAVE_WORLD_BLOCK_LEN)?;
if read_u32_at(bytes, next_chunk_tag_offset) != Some(RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG) {
continue;
}
let selected_company_id_offset =
payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET;
let selected_chairman_profile_id_offset =
payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET;
let chairman_slot_selector_offset =
payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET;
let campaign_override_flag_offset =
payload_offset + RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET;
let chairman_role_gate_offset =
payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET;
let selected_company_id = read_u32_at(bytes, selected_company_id_offset)?;
let selected_chairman_profile_id = read_u32_at(bytes, selected_chairman_profile_id_offset)?;
let chairman_slot_selectors = bytes
.get(
chairman_slot_selector_offset
..chairman_slot_selector_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT,
)?
.to_vec();
let campaign_override_flag = *bytes.get(campaign_override_flag_offset)?;
let chairman_role_gate_bytes = (0..RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT)
.map(|slot_index| {
bytes
.get(
chairman_role_gate_offset
+ slot_index * RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE,
)
.copied()
})
.collect::<Option<Vec<_>>>()?;
return Some(SmpSaveWorldSelectionContextProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-selected-company-and-chairman-context".to_string(),
chunk_tag_offset,
payload_offset,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
selected_company_id_offset,
selected_company_id,
selected_company_id_hex: format!("0x{selected_company_id:08x}"),
selected_chairman_profile_id_offset,
selected_chairman_profile_id,
selected_chairman_profile_id_hex: format!("0x{selected_chairman_profile_id:08x}"),
chairman_slot_selector_offset,
chairman_slot_selectors,
campaign_override_flag_offset,
campaign_override_flag,
campaign_override_flag_hex: format!("0x{campaign_override_flag:02x}"),
chairman_role_gate_offset,
chairman_role_gate_bytes,
evidence: vec![
format!(
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
),
format!(
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
),
format!(
"selected company id comes from payload +0x{:x} ([world+0x21])",
RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET
),
format!(
"selected chairman profile id comes from payload +0x{:x} ([world+0x25])",
RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET
),
format!(
"16 chairman slot selector bytes come from payload +0x{:x} ([world+0x87])",
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
),
format!(
"campaign override flag comes from payload +0x{:x} ([world+0xc5])",
RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET
),
format!(
"chairman role-gate bytes come from payload +0x{:x} + slot*0x{:x} ([world+0x0bc3+slot*9])",
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET,
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE
),
],
});
}
None
}
fn parse_save_world_issue_37_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveWorldIssue37Probe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
for chunk_tag_offset in find_u32_le_offsets(bytes, RT3_SAVE_WORLD_BLOCK_CHUNK_TAG) {
let payload_offset = chunk_tag_offset + 4;
let next_chunk_tag_offset = payload_offset.checked_add(RT3_SAVE_WORLD_BLOCK_LEN)?;
if read_u32_at(bytes, next_chunk_tag_offset) != Some(RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG) {
continue;
}
let issue_value_lane = build_save_dword_candidate(
bytes,
payload_offset,
"issue_0x37_value",
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET,
)?;
let issue_37_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET,
)?;
let issue_38_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET + 1,
)?;
let issue_39_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET + 2,
)?;
let issue_3a_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET + 3,
)?;
let multiplier_lane = build_save_dword_candidate(
bytes,
payload_offset,
"issue_0x37_multiplier",
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET,
)?;
let issue_opinion_base_terms_raw_i32 = build_save_i32_term_strip(
bytes,
payload_offset,
RT3_SAVE_WORLD_BLOCK_ISSUE_OPINION_BASE_TERMS_OFFSET,
RT3_SAVE_WORLD_BLOCK_ISSUE_OPINION_TERM_COUNT,
)?;
return Some(SmpSaveWorldIssue37Probe {
profile_family: profile.profile_family.clone(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-save-world-issue-0x37".to_string(),
chunk_tag_offset,
payload_offset,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
issue_37_raw_u8,
issue_37_raw_hex: format!("0x{issue_37_raw_u8:02x}"),
issue_38_raw_u8,
issue_38_raw_hex: format!("0x{issue_38_raw_u8:02x}"),
issue_39_raw_u8,
issue_39_raw_hex: format!("0x{issue_39_raw_u8:02x}"),
issue_3a_raw_u8,
issue_3a_raw_hex: format!("0x{issue_3a_raw_u8:02x}"),
issue_value_lane,
multiplier_lane,
issue_opinion_base_terms_raw_i32,
evidence: vec![
format!(
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
),
format!(
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
),
format!(
"issue value lane uses payload +0x{:x} ([world+0x2d]); atlas notes tie 0x004339b0 to the clamped 0..4 issue-0x37 setter there",
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET
),
format!(
"multiplier lane uses payload +0x{:x} ([world+0x29]); atlas notes tie 0x004339b0 to one companion scalar at that lane before company share-price refresh",
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET
),
format!(
"the adjacent byte strip at payload +0x{:x}..+0x{:x} carries raw issue slots 0x37..0x3a as {:02x} {:02x} {:02x} {:02x}",
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET,
RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET + 3,
issue_37_raw_u8,
issue_38_raw_u8,
issue_39_raw_u8,
issue_3a_raw_u8
),
],
});
}
None
}
fn parse_save_world_finance_neighborhood_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveWorldFinanceNeighborhoodProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
for chunk_tag_offset in find_u32_le_offsets(bytes, RT3_SAVE_WORLD_BLOCK_CHUNK_TAG) {
let payload_offset = chunk_tag_offset + 4;
let next_chunk_tag_offset = payload_offset.checked_add(RT3_SAVE_WORLD_BLOCK_LEN)?;
if read_u32_at(bytes, next_chunk_tag_offset) != Some(RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG) {
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 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,
"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 stock_policy_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_STOCK_POLICY_RELATIVE_OFFSET,
)?;
let bond_policy_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_BOND_POLICY_RELATIVE_OFFSET,
)?;
let bankruptcy_policy_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_BANKRUPTCY_POLICY_RELATIVE_OFFSET,
)?;
let dividend_policy_raw_u8 = read_u8_at(
bytes,
payload_offset + RT3_SAVE_WORLD_BLOCK_DIVIDEND_POLICY_RELATIVE_OFFSET,
)?;
let building_density_growth_setting_lane = build_save_dword_candidate(
bytes,
payload_offset,
"building_density_growth_setting",
RT3_SAVE_WORLD_BLOCK_BUILDING_DENSITY_GROWTH_RELATIVE_OFFSET,
)?;
let dword_candidates =
build_save_world_finance_neighborhood_candidates(bytes, payload_offset)?;
return Some(SmpSaveWorldFinanceNeighborhoodProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-save-world-finance-neighborhood".to_string(),
chunk_tag_offset,
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,
absolute_counter_mirror_lane,
stock_policy_raw_u8,
stock_policy_raw_hex: format!("0x{stock_policy_raw_u8:02x}"),
bond_policy_raw_u8,
bond_policy_raw_hex: format!("0x{bond_policy_raw_u8:02x}"),
bankruptcy_policy_raw_u8,
bankruptcy_policy_raw_hex: format!("0x{bankruptcy_policy_raw_u8:02x}"),
dividend_policy_raw_u8,
dividend_policy_raw_hex: format!("0x{dividend_policy_raw_u8:02x}"),
building_density_growth_setting_lane,
dword_candidates,
evidence: vec![
format!(
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
),
format!(
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
),
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
),
format!(
"payload +0x{:x}/+0x{:x}/+0x{:x}/+0x{:x} carry the stock, bond, bankruptcy, and dividend finance-policy bytes mirrored from scenario offsets 0x4a87/0x4a8b/0x4a8f/0x4a93",
RT3_SAVE_WORLD_BLOCK_STOCK_POLICY_RELATIVE_OFFSET,
RT3_SAVE_WORLD_BLOCK_BOND_POLICY_RELATIVE_OFFSET,
RT3_SAVE_WORLD_BLOCK_BANKRUPTCY_POLICY_RELATIVE_OFFSET,
RT3_SAVE_WORLD_BLOCK_DIVIDEND_POLICY_RELATIVE_OFFSET
),
format!(
"payload +0x{:x} carries the fixed-world building-density growth setting mirrored from `[world+0x4c7c]`, which the annual repurchase and dividend policy helpers both read directly",
RT3_SAVE_WORLD_BLOCK_BUILDING_DENSITY_GROWTH_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(),
],
});
}
None
}
fn build_save_world_finance_neighborhood_candidates(
bytes: &[u8],
payload_offset: usize,
) -> Option<Vec<SmpSaveDwordCandidate>> {
(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>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveWorldEconomicTuningProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let supported = matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
);
if !supported {
return None;
}
for chunk_tag_offset in find_u32_le_offsets(bytes, RT3_SAVE_WORLD_BLOCK_CHUNK_TAG) {
let payload_offset = chunk_tag_offset + 4;
let next_chunk_tag_offset = payload_offset.checked_add(RT3_SAVE_WORLD_BLOCK_LEN)?;
if read_u32_at(bytes, next_chunk_tag_offset) != Some(RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG) {
continue;
}
let mirror_lane = build_save_dword_candidate(
bytes,
payload_offset,
"economic_tuning_mirror_lane_0",
RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_MIRROR_RELATIVE_OFFSET,
)?;
let tuning_lanes = RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_PRIMARY_RELATIVE_OFFSETS
.iter()
.enumerate()
.map(|(lane_index, relative_offset)| {
build_save_dword_candidate(
bytes,
payload_offset,
&format!("economic_tuning_lane_{lane_index}"),
*relative_offset,
)
})
.collect::<Option<Vec<_>>>()?;
return Some(SmpSaveWorldEconomicTuningProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-save-world-economic-tuning".to_string(),
chunk_tag_offset,
payload_offset,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
mirror_lane,
tuning_lanes,
evidence: vec![
format!(
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
),
format!(
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
),
format!(
"mirror lane uses payload +0x{:x} ([world+0x0bde])",
RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_MIRROR_RELATIVE_OFFSET
),
format!(
"primary tuning lanes use payload offsets {} matching the documented [world+0x0be2..+0x0bf6] float block",
RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_PRIMARY_RELATIVE_OFFSETS
.iter()
.map(|offset| format!("0x{offset:x}"))
.collect::<Vec<_>>()
.join(", ")
),
"Current atlas evidence keeps this fixed six-float world tuning band separate from the issue-0x37 investor-confidence lane."
.to_string(),
],
});
}
None
}
fn parse_save_company_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
parse_save_tagged_collection_header_probe(
bytes,
file_extension_hint,
container_profile,
0x000061a9,
0x000061aa,
0x000061ab,
"save-company-tagged-header-counts",
"scenario-save-company-header-counts",
|header| {
header.direct_collection_flag == 1
&& header.live_id_bound >= 1
&& header.live_id_bound <= 0x20
&& header.live_record_count <= header.live_id_bound
&& header.direct_record_stride >= 0x1000
},
vec![
"save-side company collection uses tagged header family 0x61a9/0x61aa/0x61ab".to_string(),
"package-save per-company callback is currently grounded as a no-op stub, so this probe only claims header-level collection counts, not per-company payload".to_string(),
],
)
}
fn parse_save_chairman_profile_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
parse_save_tagged_collection_header_probe(
bytes,
file_extension_hint,
container_profile,
0x00005209,
0x0000520a,
0x0000520b,
"save-chairman-profile-tagged-header-counts",
"scenario-save-chairman-profile-header-counts",
|header| {
header.direct_collection_flag == 1
&& header.live_id_bound >= 1
&& header.live_id_bound <= 0x20
&& header.live_record_count <= header.live_id_bound
&& header.direct_record_stride >= 0x800
&& header.direct_record_stride <= 0x2000
},
vec![
"save-side chairman/profile collection uses tagged header family 0x5209/0x520a/0x520b".to_string(),
"the direct-record chairman/profile family is the large-stride tagged collection with embedded name and biography payload, not the smaller train-side 0x5209 family".to_string(),
],
)
}
fn parse_save_train_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
parse_save_tagged_collection_header_probe(
bytes,
file_extension_hint,
container_profile,
0x00005209,
0x0000520a,
0x0000520b,
"save-train-tagged-header-counts",
"scenario-save-train-header-counts",
|header| {
header.direct_collection_flag == 1
&& header.direct_record_stride >= 0x100
&& header.direct_record_stride <= 0x400
&& header.live_id_bound >= 0x10
&& header.live_id_bound <= 0x100
&& header.live_record_count >= 1
&& header.live_record_count <= header.live_id_bound
},
vec![
"save-side live train collection shares tagged header family 0x5209/0x520a/0x520b with other indexed direct-record bundles".to_string(),
"the grounded train-side candidate is the smaller direct-record family with stride 0x1d5 whose metadata payload carries Train N labels, distinct from the larger chairman/profile family and the non-direct region family".to_string(),
],
)
}
fn parse_save_train_collection_directory_probe(
bytes: &[u8],
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpSaveTrainCollectionDirectoryProbe> {
let header_probe = header_probe?;
if header_probe.source_kind != "save-train-tagged-header-counts" {
return None;
}
let metadata_payload =
bytes.get(header_probe.metadata_tag_offset + 4..header_probe.records_tag_offset)?;
let directory_root_byte_offset =
SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX.checked_mul(4)?;
let live_record_count = header_probe.live_record_count as usize;
let directory_len_dwords =
live_record_count.checked_mul(SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT)?;
let directory_len_bytes = directory_len_dwords.checked_mul(4)?;
let directory_bytes = metadata_payload.get(
directory_root_byte_offset..directory_root_byte_offset.checked_add(directory_len_bytes)?,
)?;
let mut entries = Vec::with_capacity(live_record_count);
for index in 0..live_record_count {
let entry_offset =
index.checked_mul(SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT * 4)?;
let payload_relative_offset = read_u32_at(directory_bytes, entry_offset)?;
let previous_live_entry_id = read_u32_at(directory_bytes, entry_offset + 4)?;
let next_live_entry_id = read_u32_at(directory_bytes, entry_offset + 8)?;
entries.push(SmpSaveTrainCollectionDirectoryEntryProbe {
live_entry_id: (index + 1) as u32,
payload_relative_offset,
payload_relative_offset_hex: format!("0x{payload_relative_offset:08x}"),
payload_absolute_offset: header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(payload_relative_offset as usize)?,
previous_live_entry_id,
previous_live_entry_id_hex: format!("0x{previous_live_entry_id:08x}"),
next_live_entry_id,
next_live_entry_id_hex: format!("0x{next_live_entry_id:08x}"),
});
}
let chain_head_live_entry_id = entries
.iter()
.find(|entry| entry.previous_live_entry_id == 0)
.map(|entry| entry.live_entry_id);
let chain_tail_live_entry_id = entries
.iter()
.find(|entry| entry.next_live_entry_id == 0)
.map(|entry| entry.live_entry_id);
let monotonic_offsets = entries
.windows(2)
.all(|window| window[0].payload_relative_offset < window[1].payload_relative_offset);
Some(SmpSaveTrainCollectionDirectoryProbe {
profile_family: header_probe.profile_family.clone(),
source_kind: "save-train-live-directory".to_string(),
semantic_family: "scenario-save-train-live-directory".to_string(),
metadata_tag_offset: header_probe.metadata_tag_offset,
records_tag_offset: header_probe.records_tag_offset,
close_tag_offset: header_probe.close_tag_offset,
directory_root_dword_index: SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX,
directory_entry_dword_count: SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT,
live_record_count: header_probe.live_record_count,
live_id_bound: header_probe.live_id_bound,
chain_head_live_entry_id,
chain_tail_live_entry_id,
entries,
evidence: vec![
"save-side train metadata payload exposes a live-entry directory immediately after the first 16 dwords, with payload-relative offsets pointing into the later records span".to_string(),
format!(
"train live directory decodes {} triplets of (payload_relative_offset, prev_live_entry_id, next_live_entry_id) from metadata dword index {}",
header_probe.live_record_count,
SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX
),
format!(
"decoded directory preserves a head/tail chain {:?}->{:?} and monotonic payload offsets={monotonic_offsets}",
chain_head_live_entry_id, chain_tail_live_entry_id
),
],
})
}
fn parse_save_region_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
let probe = parse_save_tagged_collection_header_probe(
bytes,
file_extension_hint,
container_profile,
0x00005209,
0x0000520a,
0x0000520b,
"save-region-tagged-header-counts",
"scenario-save-region-header-counts",
|header| {
header.direct_collection_flag == 0
&& header.direct_record_stride == 0x06
&& header.live_id_bound >= 0x80
&& header.live_id_bound <= 0x200
&& header.live_record_count >= 0x80
&& header.live_record_count <= header.live_id_bound
},
vec![
"save-side live region collection shares tagged header family 0x5209/0x520a/0x520b with trains and chairman profiles, but uses the larger non-direct indexed family".to_string(),
"the grounded region-side candidate is the non-direct 0x5209 family with live_id_bound/count in the 0x96/0x91 range and Marker09-style default stems in the records span, distinct from the smaller direct train family".to_string(),
],
)?;
let records_preview = bytes
.get(probe.records_tag_offset + 4..probe.close_tag_offset)
.unwrap_or(&[]);
records_preview
.windows("Marker09".len())
.any(|window| window == b"Marker09")
.then_some(probe)
}
fn parse_save_region_record_triplet_probe(
bytes: &[u8],
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpSaveRegionRecordTripletProbe> {
let header_probe = header_probe?;
if header_probe.source_kind != "save-region-tagged-header-counts" {
return None;
}
let records_payload =
bytes.get(header_probe.records_tag_offset + 4..header_probe.close_tag_offset)?;
let name_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_NAME_TAG);
let policy_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_POLICY_TAG);
let profile_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_PROFILE_TAG);
let record_count = header_probe.live_record_count as usize;
if name_offsets.len() != record_count
|| policy_offsets.len() != record_count
|| profile_offsets.len() != record_count
{
return None;
}
let region_payload_start_offsets = bytes
.get(header_probe.metadata_tag_offset + 4..header_probe.records_tag_offset)
.and_then(|metadata_payload| {
let directory_root_byte_offset =
SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX.checked_mul(4)?;
let directory_len_dwords =
record_count.checked_mul(SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT)?;
let directory_len_bytes = directory_len_dwords.checked_mul(4)?;
let directory_bytes = metadata_payload.get(
directory_root_byte_offset
..directory_root_byte_offset.checked_add(directory_len_bytes)?,
)?;
let records_payload_absolute_offset = header_probe.records_tag_offset.checked_add(4)?;
(0..record_count)
.map(|index| {
let entry_offset = index
.checked_mul(SAVE_REGION_COLLECTION_DIRECTORY_ENTRY_DWORD_COUNT * 4)?;
let payload_relative_offset =
read_u32_at(directory_bytes, entry_offset)? as usize;
let payload_absolute_offset = header_probe
.metadata_tag_offset
.checked_add(4)?
.checked_add(payload_relative_offset)?;
let payload_start =
payload_absolute_offset.checked_sub(records_payload_absolute_offset)?;
(payload_start <= records_payload.len()).then_some(payload_start)
})
.collect::<Option<Vec<_>>>()
})
.unwrap_or_else(|| name_offsets.clone());
let mut entries = Vec::with_capacity(record_count);
for index in 0..record_count {
let record_payload_relative_offset = region_payload_start_offsets[index];
let name_tag_relative_offset = name_offsets[index];
let policy_tag_relative_offset = policy_offsets[index];
let profile_tag_relative_offset = profile_offsets[index];
let next_record_relative_offset = name_offsets
.get(index + 1)
.copied()
.unwrap_or(records_payload.len());
if record_payload_relative_offset > name_tag_relative_offset {
return None;
}
if !(name_tag_relative_offset < policy_tag_relative_offset
&& policy_tag_relative_offset < profile_tag_relative_offset
&& profile_tag_relative_offset < next_record_relative_offset)
{
return None;
}
let pre_name_prefix =
records_payload.get(record_payload_relative_offset..name_tag_relative_offset)?;
let pre_name_prefix_dword_candidates = build_region_record_prefix_dword_candidates(
record_payload_relative_offset,
pre_name_prefix,
);
let name_payload =
records_payload.get(name_tag_relative_offset + 4..policy_tag_relative_offset)?;
let name = parse_save_len_prefixed_ascii_name(name_payload)?;
let policy_chunk_len =
profile_tag_relative_offset.checked_sub(policy_tag_relative_offset + 4)?;
if policy_chunk_len != 0x1a {
return None;
}
let policy_payload =
records_payload.get(policy_tag_relative_offset + 4..profile_tag_relative_offset)?;
let policy_leading_f32_0 = f32::from_bits(read_u32_at(policy_payload, 0)?);
let policy_leading_f32_1 = f32::from_bits(read_u32_at(policy_payload, 4)?);
let policy_leading_f32_2 = f32::from_bits(read_u32_at(policy_payload, 8)?);
let mut policy_reserved_dwords = Vec::with_capacity(3);
let mut policy_reserved_dword_candidates = Vec::with_capacity(3);
for dword_index in 0..3 {
let reserved_relative_offset = 12 + dword_index * 4;
let raw_u32 = read_u32_at(policy_payload, reserved_relative_offset)?;
policy_reserved_dwords.push(raw_u32);
let relative_offset = record_payload_relative_offset
+ policy_tag_relative_offset
+ 4
+ reserved_relative_offset;
policy_reserved_dword_candidates.push(SmpSaveDwordCandidate {
label: format!("policy_reserved_word_{}", dword_index + 1),
relative_offset,
relative_offset_hex: format!("0x{relative_offset:x}"),
raw_u32,
raw_u32_hex: format!("0x{raw_u32:08x}"),
value_i32: raw_u32 as i32,
value_f32: f32::from_bits(raw_u32),
});
}
let policy_trailing_word = read_u16_at(policy_payload, 24)?;
let profile_chunk_len =
next_record_relative_offset.checked_sub(profile_tag_relative_offset + 4)?;
let profile_payload =
records_payload.get(profile_tag_relative_offset + 4..next_record_relative_offset)?;
let profile_collection = parse_save_region_profile_collection_probe(profile_payload);
entries.push(SmpSaveRegionRecordTripletEntryProbe {
record_index: index,
name,
record_payload_relative_offset,
record_payload_relative_offset_hex: format!("0x{record_payload_relative_offset:x}"),
name_tag_relative_offset,
policy_tag_relative_offset,
profile_tag_relative_offset,
pre_name_prefix_len: pre_name_prefix.len(),
pre_name_prefix_hex_bytes: pre_name_prefix
.iter()
.map(|byte| format!("0x{byte:02x}"))
.collect(),
pre_name_prefix_dword_candidates,
policy_chunk_len,
profile_chunk_len,
policy_leading_f32_0,
policy_leading_f32_1,
policy_leading_f32_2,
policy_reserved_dwords,
policy_reserved_dword_candidates,
policy_trailing_word,
policy_trailing_word_hex: format!("0x{policy_trailing_word:04x}"),
profile_collection,
});
}
let zero_trailing_padding_record_count = entries
.iter()
.filter(|entry| {
entry
.profile_collection
.as_ref()
.is_some_and(|collection| collection.trailing_padding_len == 0)
})
.count();
let records_with_nonzero_pre_name_prefix = entries
.iter()
.filter(|entry| entry.pre_name_prefix_len != 0)
.count();
let records_with_prefix_dword_candidates = entries
.iter()
.filter(|entry| !entry.pre_name_prefix_dword_candidates.is_empty())
.count();
let records_with_any_nonzero_policy_reserved_dword = entries
.iter()
.filter(|entry| {
entry
.policy_reserved_dwords
.iter()
.any(|raw_u32| *raw_u32 != 0)
})
.count();
let policy_reserved_nonzero_counts = (0..3)
.map(|dword_index| {
entries
.iter()
.filter(|entry| entry.policy_reserved_dwords[dword_index] != 0)
.count()
})
.collect::<Vec<_>>();
let unique_nonzero_policy_reserved_triplets = entries
.iter()
.filter_map(|entry| {
let triplet = [
entry.policy_reserved_dwords[0],
entry.policy_reserved_dwords[1],
entry.policy_reserved_dwords[2],
];
triplet
.iter()
.any(|raw_u32| *raw_u32 != 0)
.then_some(triplet)
})
.collect::<BTreeSet<_>>()
.into_iter()
.collect::<Vec<_>>();
let unique_pre_name_prefix_lens = entries
.iter()
.map(|entry| entry.pre_name_prefix_len)
.collect::<BTreeSet<_>>()
.into_iter()
.collect::<Vec<_>>();
Some(SmpSaveRegionRecordTripletProbe {
profile_family: header_probe.profile_family.clone(),
source_kind: "save-region-record-triplets".to_string(),
semantic_family: "scenario-save-region-record-triplets".to_string(),
records_tag_offset: header_probe.records_tag_offset,
close_tag_offset: header_probe.close_tag_offset,
record_count,
entries,
evidence: vec![
"save-side region records in the non-direct Marker09 family are serialized as repeated 0x55f1/0x55f2/0x55f3 triplets inside the records span".to_string(),
format!(
"decoded {} region record triplets with one len-prefixed name chunk, one fixed policy chunk, and one trailing profile payload chunk per record",
record_count
),
"each fixed 0x55f2 policy chunk currently decodes as three leading f32 lanes, three reserved dwords, and one trailing u16 word".to_string(),
"the trailing 0x55f3 payload also carries an embedded direct profile collection with fixed 0x22-byte rows on grounded saves".to_string(),
format!(
"live-entry directory now also grounds the actual 0x520a payload starts: {} of {} records currently have nonzero bytes before the first 0x55f1 tag, with unique pre-name prefix lengths {:?}",
records_with_nonzero_pre_name_prefix,
record_count,
unique_pre_name_prefix_lens
),
format!(
"structured pre-name prefix dword candidates are currently present on {} of {} decoded region records",
records_with_prefix_dword_candidates,
record_count
),
format!(
"fixed 0x55f2 policy reserved dwords are nonzero on {} of {} decoded region records, with per-word nonzero counts {:?} and unique nonzero triplets {:?}",
records_with_any_nonzero_policy_reserved_dword,
record_count,
policy_reserved_nonzero_counts,
unique_nonzero_policy_reserved_triplets
),
format!(
"on grounded saves the 0x55f3 payload is fully consumed by that embedded profile collection: all {} decoded records currently have zero trailing padding beyond the direct profile rows",
zero_trailing_padding_record_count
),
],
})
}
fn build_region_record_prefix_dword_candidates(
record_payload_relative_offset: usize,
prefix_bytes: &[u8],
) -> Vec<SmpSaveDwordCandidate> {
prefix_bytes
.chunks_exact(4)
.enumerate()
.map(|(index, chunk)| {
let raw_u32 = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
let relative_offset = record_payload_relative_offset + index * 4;
SmpSaveDwordCandidate {
label: format!("pre_name_prefix_word_{}", index + 1),
relative_offset,
relative_offset_hex: format!("0x{relative_offset:x}"),
raw_u32,
raw_u32_hex: format!("0x{raw_u32:08x}"),
value_i32: raw_u32 as i32,
value_f32: f32::from_bits(raw_u32),
}
})
.collect()
}
fn parse_save_region_queued_notice_record_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
region_header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpSaveRegionQueuedNoticeRecordProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let max_region_id = region_header_probe
.map(|probe| probe.live_id_bound)
.unwrap_or(0x1000);
let entries = find_u32_le_offsets(bytes, SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED)
.into_iter()
.filter_map(|payload_seed_offset| {
let node_base_offset = payload_seed_offset.checked_sub(4)?;
let _node_bytes = bytes
.get(node_base_offset..node_base_offset + SAVE_REGION_QUEUED_NOTICE_NODE_LEN)?;
let next_link_raw = read_u32_at(bytes, node_base_offset)?;
let kind = read_u32_at(bytes, node_base_offset + 8)?;
let promotion_latch_dword = read_u32_at(bytes, node_base_offset + 12)?;
let region_id = read_u32_at(bytes, node_base_offset + 16)?;
let amount = read_u32_at(bytes, node_base_offset + 20)?;
let trailing_sentinel_i32_0 = read_i32_at(bytes, node_base_offset + 24)?;
let trailing_sentinel_i32_1 = read_i32_at(bytes, node_base_offset + 28)?;
if !(kind == SAVE_REGION_QUEUED_NOTICE_NODE_KIND
&& promotion_latch_dword == 0
&& region_id >= 1
&& region_id <= max_region_id
&& amount > 0
&& trailing_sentinel_i32_0 == -1
&& trailing_sentinel_i32_1 == -1)
{
return None;
}
Some(SmpSaveRegionQueuedNoticeRecordEntryProbe {
node_base_offset,
payload_seed_offset,
next_link_raw,
next_link_raw_hex: format!("0x{next_link_raw:08x}"),
payload_seed_dword: SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED,
payload_seed_dword_hex: format!("0x{SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED:08x}"),
kind,
kind_hex: format!("0x{kind:08x}"),
promotion_latch_dword,
promotion_latch_dword_hex: format!("0x{promotion_latch_dword:08x}"),
region_id,
region_id_hex: format!("0x{region_id:08x}"),
amount,
amount_hex: format!("0x{amount:08x}"),
trailing_sentinel_i32_0,
trailing_sentinel_i32_0_hex: format!("0x{:08x}", trailing_sentinel_i32_0 as u32),
trailing_sentinel_i32_1,
trailing_sentinel_i32_1_hex: format!("0x{:08x}", trailing_sentinel_i32_1 as u32),
})
})
.collect::<Vec<_>>();
if entries.is_empty() {
return None;
}
Some(SmpSaveRegionQueuedNoticeRecordProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-region-queued-notice-records".to_string(),
semantic_family: "scenario-save-region-queued-notice-records".to_string(),
payload_seed_dword: SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED,
payload_seed_dword_hex: format!("0x{SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED:08x}"),
entries,
evidence: vec![
"save-side scan searches for the grounded region queued-notice payload seed 0x005c87a8 and validates the full 0x20-byte node shape from the atlas-backed queue owner".to_string(),
"accepted nodes require kind=7, promotion-latch dword=0, a bounded live region id, a positive amount, and trailing sentinel dwords -1/-1".to_string(),
],
})
}
fn parse_save_region_fixed_row_run_candidate_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
region_header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpSaveRegionFixedRowRunCandidateProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
let region_header_probe = region_header_probe?;
let target_row_count = region_header_probe.live_record_count as usize;
if target_row_count == 0 {
return None;
}
let scan_end_offset = region_header_probe.metadata_tag_offset;
let row_span_len = target_row_count.checked_mul(SAVE_REGION_FIXED_ROW_STRIDE)?;
let scan_bytes = bytes.get(..scan_end_offset)?;
let mut candidates = find_u32_le_offsets(scan_bytes, region_header_probe.live_record_count)
.into_iter()
.filter_map(|count_offset| {
let rows_offset = count_offset.checked_add(4)?;
let rows_end_offset = rows_offset.checked_add(row_span_len)?;
if rows_end_offset > scan_end_offset {
return None;
}
let rows_bytes = bytes.get(rows_offset..rows_end_offset)?;
let mut dword_lane_summaries =
Vec::with_capacity(SAVE_REGION_FIXED_ROW_DWORD_LANE_COUNT);
let mut best_probable_density_lane = None::<(usize, usize)>;
for lane_index in 0..SAVE_REGION_FIXED_ROW_DWORD_LANE_COUNT {
let relative_offset = lane_index * 4;
let mut zero_count = 0usize;
let mut nonzero_count = 0usize;
let mut probable_normal_f32_count = 0usize;
let mut small_unsigned_count = 0usize;
let mut distinct_values = BTreeSet::new();
let mut sample_values_hex = Vec::new();
for row_index in 0..target_row_count {
let row_offset = row_index * SAVE_REGION_FIXED_ROW_STRIDE + relative_offset;
let raw_u32 = read_u32_at(rows_bytes, row_offset)?;
if raw_u32 == 0 {
zero_count += 1;
} else {
nonzero_count += 1;
}
if probable_normal_f32_string(raw_u32).is_some() {
probable_normal_f32_count += 1;
}
if raw_u32 <= 1024 {
small_unsigned_count += 1;
}
if distinct_values.insert(raw_u32) && sample_values_hex.len() < 6 {
sample_values_hex.push(format!("0x{raw_u32:08x}"));
}
}
if best_probable_density_lane
.is_none_or(|(_, best_count)| probable_normal_f32_count > best_count)
{
best_probable_density_lane = Some((relative_offset, probable_normal_f32_count));
}
dword_lane_summaries.push(SmpSaveFixedRowRunDwordLaneSummary {
relative_offset,
relative_offset_hex: format!("0x{relative_offset:x}"),
zero_count,
nonzero_count,
distinct_value_count: distinct_values.len(),
probable_normal_f32_count,
small_unsigned_count,
sample_values_hex,
});
}
let mut trailing_values = BTreeSet::new();
let mut trailing_byte_zero_count = 0usize;
let mut trailing_byte_nonzero_count = 0usize;
let mut trailing_byte_sample_values_hex = Vec::new();
for row_index in 0..target_row_count {
let value = *rows_bytes.get(row_index * SAVE_REGION_FIXED_ROW_STRIDE + 0x28)?;
if value == 0 {
trailing_byte_zero_count += 1;
} else {
trailing_byte_nonzero_count += 1;
}
if trailing_values.insert(value) && trailing_byte_sample_values_hex.len() < 8 {
trailing_byte_sample_values_hex.push(format!("0x{value:02x}"));
}
}
let shape_signature = build_save_region_fixed_row_run_candidate_shape_signature(
&dword_lane_summaries,
trailing_byte_zero_count,
trailing_values.len(),
target_row_count,
);
let shape_family_signature =
build_save_region_fixed_row_run_candidate_shape_family_signature(
&dword_lane_summaries,
trailing_byte_zero_count,
trailing_values.len(),
target_row_count,
);
Some(SmpSaveRegionFixedRowRunCandidate {
count_offset,
count_offset_hex: format!("0x{count_offset:x}"),
row_count: target_row_count,
row_stride: SAVE_REGION_FIXED_ROW_STRIDE,
row_stride_hex: format!("0x{:x}", SAVE_REGION_FIXED_ROW_STRIDE),
rows_offset,
rows_offset_hex: format!("0x{rows_offset:x}"),
rows_end_offset,
rows_end_offset_hex: format!("0x{rows_end_offset:x}"),
distance_to_region_metadata_tag: scan_end_offset.saturating_sub(rows_end_offset),
distance_to_region_metadata_tag_hex: format!(
"0x{:x}",
scan_end_offset.saturating_sub(rows_end_offset)
),
dword_lane_summaries,
shape_signature,
shape_family_signature,
trailing_byte_zero_count,
trailing_byte_nonzero_count,
trailing_byte_distinct_value_count: trailing_values.len(),
trailing_byte_sample_values_hex,
best_probable_density_lane_relative_offset_hex: best_probable_density_lane
.filter(|(_, count)| *count != 0)
.map(|(relative_offset, _)| format!("0x{relative_offset:x}")),
})
})
.collect::<Vec<_>>();
candidates.sort_by_key(|candidate| {
(
Reverse(
candidate
.dword_lane_summaries
.iter()
.map(|summary| summary.probable_normal_f32_count)
.max()
.unwrap_or_default(),
),
candidate.distance_to_region_metadata_tag,
candidate.count_offset,
)
});
candidates.truncate(SAVE_REGION_FIXED_ROW_CANDIDATE_PROBE_LIMIT);
let candidate_count = candidates.len();
let best_candidate_offset_hex = candidates
.first()
.map(|candidate| candidate.rows_offset_hex.clone());
Some(SmpSaveRegionFixedRowRunCandidateProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-region-fixed-row-run-candidates".to_string(),
semantic_family: "scenario-save-region-fixed-row-run-candidates".to_string(),
target_row_count,
target_row_stride: SAVE_REGION_FIXED_ROW_STRIDE,
target_row_stride_hex: format!("0x{:x}", SAVE_REGION_FIXED_ROW_STRIDE),
scan_start_offset: 0,
scan_start_offset_hex: "0x0".to_string(),
scan_end_offset,
scan_end_offset_hex: format!("0x{scan_end_offset:x}"),
candidates,
evidence: vec![
format!(
"candidate scan looks for pre-region-header counted runs keyed to the grounded live region count {} with fixed row stride 0x{:x}",
target_row_count, SAVE_REGION_FIXED_ROW_STRIDE
),
format!(
"current scan range ends at region metadata tag offset 0x{:x}, because the atlas restore order places the fixed rows before the tagged 0x5209/0x520a/0x520b region collection",
scan_end_offset
),
format!(
"kept {} highest-signal candidates after sorting by probable-f32 lane density and proximity to the region metadata tag; best candidate rows offset is {:?}",
candidate_count, best_candidate_offset_hex
),
],
})
}
fn build_save_region_fixed_row_run_candidate_shape_signature(
dword_lane_summaries: &[SmpSaveFixedRowRunDwordLaneSummary],
trailing_byte_zero_count: usize,
trailing_byte_distinct_value_count: usize,
row_count: usize,
) -> String {
fn pick_lane_terms<F, P>(
summaries: &[SmpSaveFixedRowRunDwordLaneSummary],
score: F,
include: P,
row_count: usize,
max_terms: usize,
) -> Vec<String>
where
F: Fn(&SmpSaveFixedRowRunDwordLaneSummary) -> usize,
P: Fn(&SmpSaveFixedRowRunDwordLaneSummary) -> bool,
{
let high_signal_threshold = row_count.saturating_mul(3) / 4;
let mut picked = summaries
.iter()
.filter(|summary| include(summary))
.filter(|summary| score(summary) >= high_signal_threshold)
.map(|summary| {
(
summary.relative_offset,
format!("{}:{}", summary.relative_offset_hex, score(summary)),
)
})
.collect::<Vec<_>>();
if picked.is_empty() {
picked = summaries
.iter()
.filter(|summary| include(summary))
.filter_map(|summary| {
let value = score(summary);
(value != 0).then(|| {
(
summary.relative_offset,
format!("{}:{}", summary.relative_offset_hex, value),
)
})
})
.collect::<Vec<_>>();
picked.sort_by_key(|(relative_offset, term)| {
let value = term
.split(':')
.nth(1)
.and_then(|part| part.parse::<usize>().ok())
.unwrap_or_default();
(Reverse(value), *relative_offset)
});
picked.truncate(max_terms);
}
picked.into_iter().map(|(_, term)| term).collect()
}
let probable_terms = pick_lane_terms(
dword_lane_summaries,
|summary| summary.probable_normal_f32_count,
|_| true,
row_count,
3,
);
let small_terms = pick_lane_terms(
dword_lane_summaries,
|summary| summary.small_unsigned_count,
|summary| summary.nonzero_count != 0,
row_count,
2,
);
let zero_terms = pick_lane_terms(
dword_lane_summaries,
|summary| summary.zero_count,
|summary| summary.zero_count != row_count,
row_count,
2,
);
format!(
"pf32=[{}]|small=[{}]|zero=[{}]|trail={}/{}",
probable_terms.join(","),
small_terms.join(","),
zero_terms.join(","),
trailing_byte_zero_count,
trailing_byte_distinct_value_count
)
}
fn build_save_region_fixed_row_run_candidate_shape_family_signature(
dword_lane_summaries: &[SmpSaveFixedRowRunDwordLaneSummary],
trailing_byte_zero_count: usize,
trailing_byte_distinct_value_count: usize,
row_count: usize,
) -> String {
let dense_pf32_offsets = dword_lane_summaries
.iter()
.filter(|summary| summary.probable_normal_f32_count >= row_count.saturating_mul(3) / 4)
.map(|summary| summary.relative_offset_hex.clone())
.collect::<Vec<_>>();
let partial_zero_offsets = dword_lane_summaries
.iter()
.filter(|summary| {
summary.zero_count != 0
&& summary.zero_count != row_count
&& summary.zero_count >= row_count.saturating_mul(5) / 100
})
.map(|summary| summary.relative_offset_hex.clone())
.collect::<Vec<_>>();
let small_nonzero_offsets = dword_lane_summaries
.iter()
.filter(|summary| {
summary.nonzero_count != 0
&& summary.small_unsigned_count >= row_count.saturating_mul(8) / 100
})
.map(|summary| summary.relative_offset_hex.clone())
.collect::<Vec<_>>();
format!(
"dense_pf32=[{}]|small_nonzero=[{}]|partial_zero=[{}]|trail_bucket={}/{}",
dense_pf32_offsets.join(","),
small_nonzero_offsets.join(","),
partial_zero_offsets.join(","),
trailing_byte_zero_count / 8,
trailing_byte_distinct_value_count / 8
)
}
fn parse_save_placed_structure_record_triplet_probe(
bytes: &[u8],
header_probe: Option<&SmpSaveTaggedCollectionHeaderProbe>,
) -> Option<SmpSavePlacedStructureRecordTripletProbe> {
let header_probe = header_probe?;
if header_probe.source_kind != "save-placed-structure-tagged-header-counts" {
return None;
}
let records_payload =
bytes.get(header_probe.records_tag_offset + 4..header_probe.close_tag_offset)?;
let name_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_NAME_TAG);
let policy_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_POLICY_TAG);
let profile_offsets = find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_PROFILE_TAG);
let record_count = header_probe.live_record_count as usize;
if name_offsets.len() != record_count
|| policy_offsets.len() != record_count
|| profile_offsets.len() != record_count
{
return None;
}
let mut entries = Vec::with_capacity(record_count);
for index in 0..record_count {
let name_tag_relative_offset = name_offsets[index];
let policy_tag_relative_offset = policy_offsets[index];
let profile_tag_relative_offset = profile_offsets[index];
let next_record_relative_offset = name_offsets
.get(index + 1)
.copied()
.unwrap_or(records_payload.len());
if !(name_tag_relative_offset < policy_tag_relative_offset
&& policy_tag_relative_offset < profile_tag_relative_offset
&& profile_tag_relative_offset < next_record_relative_offset)
{
return None;
}
let name_payload =
records_payload.get(name_tag_relative_offset + 4..policy_tag_relative_offset)?;
let (primary_name, secondary_name) = parse_save_len_prefixed_ascii_name_pair(name_payload)?;
let policy_chunk_len =
profile_tag_relative_offset.checked_sub(policy_tag_relative_offset + 4)?;
if policy_chunk_len != 0x1a {
return None;
}
let policy_payload =
records_payload.get(policy_tag_relative_offset + 4..profile_tag_relative_offset)?;
let policy_f32_lane_0 = f32::from_bits(read_u32_at(policy_payload, 0)?);
let policy_f32_lane_1 = f32::from_bits(read_u32_at(policy_payload, 4)?);
let policy_f32_lane_2 = f32::from_bits(read_u32_at(policy_payload, 8)?);
let policy_f32_lane_3 = f32::from_bits(read_u32_at(policy_payload, 12)?);
let policy_f32_lane_4 = f32::from_bits(read_u32_at(policy_payload, 16)?);
let policy_reserved_dword = read_u32_at(policy_payload, 20)?;
let policy_trailing_word = read_u16_at(policy_payload, 24)?;
let profile_chunk_len =
next_record_relative_offset.checked_sub(profile_tag_relative_offset + 4)?;
let profile_payload =
records_payload.get(profile_tag_relative_offset + 4..next_record_relative_offset)?;
let profile_open_marker = read_u32_at(profile_payload, 0)?;
if profile_open_marker != 0x00005dc1 {
return None;
}
let (profile_repeated_primary_name, profile_repeated_secondary_name) =
parse_save_len_prefixed_ascii_name_pair(profile_payload.get(4..)?)?;
let mut trailer_offset = 4usize;
let repeated_primary_len = *profile_payload.get(trailer_offset)? as usize;
trailer_offset += 1 + repeated_primary_len;
while matches!(profile_payload.get(trailer_offset), Some(0)) {
trailer_offset += 1;
}
let repeated_secondary_len = *profile_payload.get(trailer_offset)? as usize;
trailer_offset += 1 + repeated_secondary_len;
let mut matched_footer = None;
for candidate_offset in [trailer_offset, trailer_offset + 1] {
if let (
Some(profile_payload_dword),
Some(profile_sentinel_i32),
Some(profile_close_marker),
) = (
read_u32_at(profile_payload, candidate_offset),
read_i32_at(profile_payload, candidate_offset + 4),
read_u32_at(profile_payload, candidate_offset + 8),
) {
if profile_close_marker == 0x00005dc2 {
matched_footer = Some((
profile_payload_dword,
profile_sentinel_i32,
profile_close_marker,
));
break;
}
}
}
let (profile_payload_dword, profile_sentinel_i32, profile_close_marker) = matched_footer?;
let (profile_status_kind, farm_growth_stage_index) =
derive_save_placed_structure_profile_status(
&primary_name,
&secondary_name,
profile_sentinel_i32,
);
entries.push(SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: index,
primary_name,
secondary_name,
name_tag_relative_offset,
policy_tag_relative_offset,
profile_tag_relative_offset,
policy_chunk_len,
profile_chunk_len,
policy_f32_lane_0,
policy_f32_lane_1,
policy_f32_lane_2,
policy_f32_lane_3,
policy_f32_lane_4,
policy_reserved_dword,
policy_trailing_word,
policy_trailing_word_hex: format!("0x{policy_trailing_word:04x}"),
profile_open_marker,
profile_open_marker_hex: format!("0x{profile_open_marker:08x}"),
profile_repeated_primary_name,
profile_repeated_secondary_name,
profile_payload_dword,
profile_payload_dword_hex: format!("0x{profile_payload_dword:08x}"),
profile_sentinel_i32,
profile_status_kind: profile_status_kind.to_string(),
farm_growth_stage_index,
profile_close_marker,
profile_close_marker_hex: format!("0x{profile_close_marker:08x}"),
});
}
let farm_growth_stage_entry_count = entries
.iter()
.filter(|entry| entry.farm_growth_stage_index.is_some())
.count();
Some(SmpSavePlacedStructureRecordTripletProbe {
profile_family: header_probe.profile_family.clone(),
source_kind: "save-placed-structure-record-triplets".to_string(),
semantic_family: "scenario-save-placed-structure-record-triplets".to_string(),
records_tag_offset: header_probe.records_tag_offset,
close_tag_offset: header_probe.close_tag_offset,
record_count,
entries,
evidence: vec![
"save-side placed-structure records are serialized as repeated 0x55f1/0x55f2/0x55f3 triplets inside the tagged records span".to_string(),
"the 0x55f1 chunk currently exposes two len-prefixed structure-name stems before the fixed 0x55f2 policy row".to_string(),
"each fixed placed-structure 0x55f2 policy chunk currently decodes as five f32-like lanes, one reserved dword, and one trailing u16 word".to_string(),
format!(
"the compact 0x55f3 footer status lane behaves like a farm growth-stage bucket on grounded saves: {farm_growth_stage_entry_count} entries expose nonnegative 0..11 values and all observed non-farm families stay at -1"
),
],
})
}
fn derive_save_placed_structure_profile_status(
primary_name: &str,
secondary_name: &str,
raw_status: i32,
) -> (&'static str, Option<u8>) {
let looks_like_farm = primary_name.starts_with("Farm") || secondary_name.contains("Farm");
if raw_status == -1 {
return ("unset", None);
}
if looks_like_farm && (0..=11).contains(&raw_status) {
return ("farm_growth_stage_bucket", Some(raw_status as u8));
}
("opaque_nondefault", None)
}
fn parse_save_placed_structure_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
parse_save_tagged_collection_header_probe(
bytes,
file_extension_hint,
container_profile,
0x000036b1,
0x000036b2,
0x000036b3,
"save-placed-structure-tagged-header-counts",
"scenario-save-placed-structure-header-counts",
|header| {
header.direct_collection_flag == 0
&& header.direct_record_stride >= 1
&& header.direct_record_stride <= 0x20
&& header.live_id_bound >= 0x100
&& header.live_record_count >= 0x100
&& header.live_record_count <= header.live_id_bound
},
vec![
"save-side placed-structure collection uses tagged family 0x36b1/0x36b2/0x36b3 beneath the wider local-runtime and route-entry rebuild owners".to_string(),
"current evidence only grounds header-level placed-structure collection counts here; direct record-body reconstruction still needs the later per-entry load/save slot study.".to_string(),
],
)
}
fn parse_save_placed_structure_dynamic_side_buffer_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSavePlacedStructureDynamicSideBufferProbe> {
#[derive(Clone)]
struct EmbeddedNameRow {
name_tag_relative_offset: usize,
prefix_leading_dword: u32,
prefix_trailing_word: u16,
prefix_separator_byte: u8,
name_payload_relative_offset: usize,
name_payload_len: usize,
primary_name: Option<String>,
secondary_name: Option<String>,
tertiary_name: Option<String>,
}
#[derive(Default)]
struct PrefixPatternAccumulator {
count: usize,
first_name_tag_relative_offset: usize,
first_primary_name: Option<String>,
first_secondary_name: Option<String>,
section_like_primary_name_count: usize,
cap_like_primary_name_count: usize,
other_primary_name_count: usize,
}
#[derive(Default)]
struct NamePairAccumulator {
count: usize,
first_name_tag_relative_offset: usize,
prefix_counts: BTreeMap<(u32, u16, u8), usize>,
}
#[derive(Clone)]
struct PayloadEnvelopeRow {
name_tag_relative_offset: usize,
primary_name: Option<String>,
secondary_name: Option<String>,
name_payload_end_relative_offset: Option<usize>,
policy_tag_relative_offset: Option<usize>,
profile_tag_relative_offset: Option<usize>,
next_name_tag_relative_offset: Option<usize>,
name_to_policy_gap_len: Option<usize>,
policy_chunk_len: Option<usize>,
profile_chunk_len_to_next_name_or_end: Option<usize>,
short_profile_first_flag_byte: Option<u8>,
short_profile_second_flag_byte: Option<u8>,
}
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
if !matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
) {
return None;
}
let metadata_offsets = find_u32_le_offsets(bytes, 0x000038a5);
let records_offsets = find_u32_le_offsets(bytes, 0x000038a6);
let close_offsets = find_u32_le_offsets(bytes, 0x000038a7);
for metadata_tag_offset in metadata_offsets {
let Some(records_tag_offset) = records_offsets
.iter()
.copied()
.find(|offset| *offset > metadata_tag_offset)
else {
continue;
};
let Some(close_tag_offset) = close_offsets
.iter()
.copied()
.find(|offset| *offset > records_tag_offset)
else {
continue;
};
let Some(payload) = bytes.get(metadata_tag_offset + 4..records_tag_offset) else {
continue;
};
if payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
continue;
}
let Some(header_words) = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT)
.map(|index| read_u32_at(payload, index * 4))
.collect::<Option<Vec<_>>>()
else {
continue;
};
let Some(header_words): Option<[u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT]> =
header_words.try_into().ok()
else {
continue;
};
let summary = IndexedCollectionHeaderSummary {
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
direct_collection_flag: header_words[0],
direct_record_stride: header_words[1],
live_id_bound: header_words[4],
live_record_count: header_words[5],
header_words,
};
if !(summary.direct_collection_flag == 0
&& summary.direct_record_stride == 0x06
&& summary.header_words.get(2) == Some(&1000)
&& summary.header_words.get(3) == Some(&500)
&& summary.header_words.get(6) == Some(&0)
&& summary.header_words.get(7) == Some(&1)
&& summary.live_id_bound >= 0x100
&& summary.live_id_bound <= 0x1000
&& summary.live_record_count >= 0x100
&& summary.live_record_count <= summary.live_id_bound)
{
continue;
}
let Some(records_payload) = bytes.get(records_tag_offset + 4..close_tag_offset) else {
continue;
};
let embedded_name_tag_offsets =
find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_NAME_TAG);
let Some(&first_embedded_name_tag_relative_offset) = embedded_name_tag_offsets.first()
else {
continue;
};
let Some(prefix_payload) = records_payload.get(..first_embedded_name_tag_relative_offset)
else {
continue;
};
if prefix_payload.len() < 7 {
continue;
}
let Some(owner_shared_dword) = read_u32_at(prefix_payload, 0) else {
continue;
};
let owner_shared_dword_relative_offset = 0usize;
let first_record_child_count_after_owner_shared = read_u16_at(records_payload, 4);
let first_record_saved_primary_child_byte_after_owner_shared =
read_u8_at(records_payload, 6);
let first_record_first_name_tag_relative_offset_after_owner_shared = (3usize..=16usize)
.find(|offset| {
read_u16_at(records_payload, 4 + *offset) == Some(SAVE_REGION_RECORD_NAME_TAG)
});
let prefix_leading_dword = owner_shared_dword;
let Some(prefix_trailing_word) = read_u16_at(prefix_payload, 4) else {
continue;
};
let Some(prefix_separator_byte) = prefix_payload.get(6).copied() else {
continue;
};
let mut parsed_embedded_names = None;
for relative_name_offset in [4usize, 6usize] {
let Some(name_payload) = records_payload
.get(first_embedded_name_tag_relative_offset + relative_name_offset..)
else {
continue;
};
if let Some(names) = parse_save_len_prefixed_ascii_name_triplet(name_payload) {
parsed_embedded_names = Some(names);
break;
}
}
let Some((
first_embedded_primary_name,
first_embedded_secondary_name,
first_embedded_tertiary_name,
)) = parsed_embedded_names
else {
continue;
};
let embedded_name_rows = embedded_name_tag_offsets
.iter()
.copied()
.filter_map(|name_tag_relative_offset| {
let prefix_payload = records_payload.get(..name_tag_relative_offset)?;
if prefix_payload.len() < 7 {
return None;
}
let prefix_leading_dword = read_u32_at(prefix_payload, prefix_payload.len() - 7)?;
let prefix_trailing_word = read_u16_at(prefix_payload, prefix_payload.len() - 3)?;
let prefix_separator_byte = *prefix_payload.last()?;
let mut parsed_names = None;
for relative_name_offset in [4usize, 6usize] {
let Some(name_payload) =
records_payload.get(name_tag_relative_offset + relative_name_offset..)
else {
continue;
};
if let Some((names, name_payload_len)) =
parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(name_payload)
{
parsed_names = Some((relative_name_offset, name_payload_len, names));
break;
}
}
let (name_payload_relative_offset, name_payload_len, names) =
parsed_names.unwrap_or((4usize, 0usize, Default::default()));
let (primary_name, secondary_name, tertiary_name) = names;
Some(EmbeddedNameRow {
name_tag_relative_offset,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
name_payload_relative_offset,
name_payload_len,
primary_name: (!primary_name.is_empty()).then_some(primary_name),
secondary_name: (!secondary_name.is_empty()).then_some(secondary_name),
tertiary_name,
})
})
.collect::<Vec<_>>();
let policy_tag_offsets =
find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_POLICY_TAG);
let profile_tag_offsets =
find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_PROFILE_TAG);
let payload_envelope_rows = embedded_name_rows
.iter()
.enumerate()
.map(|(row_index, row)| {
let next_name_tag_relative_offset = embedded_name_tag_offsets
.get(row_index + 1)
.copied()
.or(Some(records_payload.len()));
let name_payload_end_relative_offset = Some(
row.name_tag_relative_offset
+ row.name_payload_relative_offset
+ row.name_payload_len,
);
let policy_tag_relative_offset =
policy_tag_offsets.iter().copied().find(|offset| {
*offset > row.name_tag_relative_offset
&& next_name_tag_relative_offset
.is_none_or(|next_name| *offset < next_name)
});
let profile_tag_relative_offset = policy_tag_relative_offset.and_then(|policy| {
profile_tag_offsets.iter().copied().find(|offset| {
*offset > policy
&& next_name_tag_relative_offset
.is_none_or(|next_name| *offset < next_name)
})
});
let name_to_policy_gap_len = name_payload_end_relative_offset
.zip(policy_tag_relative_offset)
.and_then(
|(name_payload_end_relative_offset, policy_tag_relative_offset)| {
policy_tag_relative_offset.checked_sub(name_payload_end_relative_offset)
},
);
let policy_chunk_len = policy_tag_relative_offset
.zip(profile_tag_relative_offset)
.and_then(
|(policy_tag_relative_offset, profile_tag_relative_offset)| {
profile_tag_relative_offset.checked_sub(policy_tag_relative_offset + 4)
},
);
let profile_chunk_len_to_next_name_or_end =
profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
next_name_tag_relative_offset.and_then(|next_name_tag_relative_offset| {
next_name_tag_relative_offset
.checked_sub(profile_tag_relative_offset + 4)
})
});
let short_profile_first_flag_byte =
profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
records_payload
.get(profile_tag_relative_offset + 4)
.copied()
});
let short_profile_second_flag_byte =
profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
records_payload
.get(profile_tag_relative_offset + 5)
.copied()
});
PayloadEnvelopeRow {
name_tag_relative_offset: row.name_tag_relative_offset,
primary_name: row.primary_name.clone(),
secondary_name: row.secondary_name.clone(),
name_payload_end_relative_offset,
policy_tag_relative_offset,
profile_tag_relative_offset,
next_name_tag_relative_offset,
name_to_policy_gap_len,
policy_chunk_len,
profile_chunk_len_to_next_name_or_end,
short_profile_first_flag_byte,
short_profile_second_flag_byte,
}
})
.collect::<Vec<_>>();
let embedded_name_row_samples = embedded_name_rows
.iter()
.take(8)
.enumerate()
.map(
|(sample_index, row)| SmpSavePlacedStructureDynamicSideBufferSampleEntry {
sample_index,
name_tag_relative_offset: row.name_tag_relative_offset,
prefix_leading_dword: row.prefix_leading_dword,
prefix_leading_dword_hex: format!("0x{:08x}", row.prefix_leading_dword),
prefix_trailing_word: row.prefix_trailing_word,
prefix_trailing_word_hex: format!("0x{:04x}", row.prefix_trailing_word),
prefix_separator_byte: row.prefix_separator_byte,
prefix_separator_byte_hex: format!("0x{:02x}", row.prefix_separator_byte),
primary_name: row.primary_name.clone(),
secondary_name: row.secondary_name.clone(),
tertiary_name: row.tertiary_name.clone(),
},
)
.collect::<Vec<_>>();
let mut compact_prefix_pattern_map =
BTreeMap::<(u32, u16, u8), PrefixPatternAccumulator>::new();
let mut name_pair_map = BTreeMap::<(String, String), NamePairAccumulator>::new();
for row in &embedded_name_rows {
let entry = compact_prefix_pattern_map
.entry((
row.prefix_leading_dword,
row.prefix_trailing_word,
row.prefix_separator_byte,
))
.or_insert_with(|| PrefixPatternAccumulator {
first_name_tag_relative_offset: row.name_tag_relative_offset,
first_primary_name: row.primary_name.clone(),
first_secondary_name: row.secondary_name.clone(),
..Default::default()
});
entry.count += 1;
match row.primary_name.as_deref() {
Some(name) if name.ends_with("_Section.3dp") => {
entry.section_like_primary_name_count += 1;
}
Some(name) if name.ends_with("_Cap.3dp") => {
entry.cap_like_primary_name_count += 1;
}
_ => {
entry.other_primary_name_count += 1;
}
}
if let (Some(primary_name), Some(secondary_name)) =
(row.primary_name.as_ref(), row.secondary_name.as_ref())
{
let entry = name_pair_map
.entry((primary_name.clone(), secondary_name.clone()))
.or_insert_with(|| NamePairAccumulator {
first_name_tag_relative_offset: row.name_tag_relative_offset,
..Default::default()
});
entry.count += 1;
*entry
.prefix_counts
.entry((
row.prefix_leading_dword,
row.prefix_trailing_word,
row.prefix_separator_byte,
))
.or_default() += 1;
}
}
let prefix_leading_dword_matching_embedded_profile_tag_count = embedded_name_rows
.iter()
.filter(|row| row.prefix_leading_dword == u32::from(SAVE_REGION_RECORD_PROFILE_TAG))
.count();
let mut compact_prefix_pattern_summaries = compact_prefix_pattern_map
.into_iter()
.map(
|(
(prefix_leading_dword, prefix_trailing_word, prefix_separator_byte),
accumulator,
)| {
SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary {
prefix_leading_dword,
prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
prefix_trailing_word,
prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
prefix_separator_byte,
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
count: accumulator.count,
first_name_tag_relative_offset: accumulator.first_name_tag_relative_offset,
prefix_leading_dword_matches_embedded_profile_tag: prefix_leading_dword
== u32::from(SAVE_REGION_RECORD_PROFILE_TAG),
section_like_primary_name_count: accumulator
.section_like_primary_name_count,
cap_like_primary_name_count: accumulator.cap_like_primary_name_count,
other_primary_name_count: accumulator.other_primary_name_count,
first_primary_name: accumulator.first_primary_name,
first_secondary_name: accumulator.first_secondary_name,
}
},
)
.collect::<Vec<_>>();
compact_prefix_pattern_summaries.sort_by(|left, right| {
right
.count
.cmp(&left.count)
.then_with(|| {
left.first_name_tag_relative_offset
.cmp(&right.first_name_tag_relative_offset)
})
.then_with(|| left.prefix_leading_dword.cmp(&right.prefix_leading_dword))
.then_with(|| left.prefix_trailing_word.cmp(&right.prefix_trailing_word))
.then_with(|| left.prefix_separator_byte.cmp(&right.prefix_separator_byte))
});
let mut name_pair_summaries = name_pair_map
.into_iter()
.filter_map(|((primary_name, secondary_name), accumulator)| {
let dominant_prefix = accumulator.prefix_counts.iter().max_by(
|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
},
)?;
let (
dominant_prefix_leading_dword,
dominant_prefix_trailing_word,
dominant_prefix_separator_byte,
) = *dominant_prefix.0;
let dominant_prefix_count = *dominant_prefix.1;
Some(SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name,
secondary_name,
count: accumulator.count,
first_name_tag_relative_offset: accumulator.first_name_tag_relative_offset,
unique_compact_prefix_pattern_count: accumulator.prefix_counts.len(),
dominant_prefix_leading_dword,
dominant_prefix_leading_dword_hex: format!(
"0x{dominant_prefix_leading_dword:08x}"
),
dominant_prefix_trailing_word,
dominant_prefix_trailing_word_hex: format!(
"0x{dominant_prefix_trailing_word:04x}"
),
dominant_prefix_separator_byte,
dominant_prefix_separator_byte_hex: format!(
"0x{dominant_prefix_separator_byte:02x}"
),
dominant_prefix_count,
})
})
.collect::<Vec<_>>();
name_pair_summaries.sort_by(|left, right| {
right
.count
.cmp(&left.count)
.then_with(|| {
left.first_name_tag_relative_offset
.cmp(&right.first_name_tag_relative_offset)
})
.then_with(|| left.primary_name.cmp(&right.primary_name))
.then_with(|| left.secondary_name.cmp(&right.secondary_name))
});
let row_count_with_policy_tag_before_next_name = payload_envelope_rows
.iter()
.filter(|row| row.policy_tag_relative_offset.is_some())
.count();
let row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope = payload_envelope_rows
.iter()
.filter(|row| {
row.policy_tag_relative_offset.is_some()
&& row.profile_tag_relative_offset.is_some()
})
.count();
let row_count_missing_policy_tag_before_next_name = payload_envelope_rows
.iter()
.filter(|row| row.policy_tag_relative_offset.is_none())
.count();
let row_count_missing_profile_tag_after_policy = payload_envelope_rows
.iter()
.filter(|row| {
row.policy_tag_relative_offset.is_some()
&& row.profile_tag_relative_offset.is_none()
})
.count();
let mut policy_chunk_len_counts = BTreeMap::<usize, usize>::new();
let mut profile_chunk_len_counts = BTreeMap::<usize, usize>::new();
for row in &payload_envelope_rows {
if let Some(policy_chunk_len) = row.policy_chunk_len {
*policy_chunk_len_counts.entry(policy_chunk_len).or_default() += 1;
}
if let Some(profile_chunk_len_to_next_name_or_end) =
row.profile_chunk_len_to_next_name_or_end
{
*profile_chunk_len_counts
.entry(profile_chunk_len_to_next_name_or_end)
.or_default() += 1;
}
}
let unique_policy_chunk_lens = policy_chunk_len_counts.keys().copied().collect::<Vec<_>>();
let unique_profile_chunk_lens =
profile_chunk_len_counts.keys().copied().collect::<Vec<_>>();
let dominant_policy_chunk_len = policy_chunk_len_counts
.iter()
.max_by(|(left_len, left_count), (right_len, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_len.cmp(left_len))
})
.map(|(len, count)| (*len, *count));
let dominant_profile_chunk_len = profile_chunk_len_counts
.iter()
.max_by(|(left_len, left_count), (right_len, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_len.cmp(left_len))
})
.map(|(len, count)| (*len, *count));
let short_profile_flag_rows = payload_envelope_rows
.iter()
.filter(|row| row.profile_chunk_len_to_next_name_or_end == Some(6))
.filter_map(|row| {
Some((
row.name_tag_relative_offset,
row.primary_name.clone(),
row.secondary_name.clone(),
row.short_profile_first_flag_byte?,
row.short_profile_second_flag_byte?,
))
})
.collect::<Vec<_>>();
let mut short_profile_flag_pair_counts = BTreeMap::<(u8, u8), usize>::new();
let mut short_profile_first_flag_counts = BTreeMap::<u8, usize>::new();
let mut short_profile_second_flag_counts = BTreeMap::<u8, usize>::new();
for (_, _, _, first_flag_byte, second_flag_byte) in &short_profile_flag_rows {
*short_profile_flag_pair_counts
.entry((*first_flag_byte, *second_flag_byte))
.or_default() += 1;
*short_profile_first_flag_counts
.entry(*first_flag_byte)
.or_default() += 1;
*short_profile_second_flag_counts
.entry(*second_flag_byte)
.or_default() += 1;
}
let dominant_short_profile_flag_pair = short_profile_flag_pair_counts
.iter()
.max_by(|(left_pair, left_count), (right_pair, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_pair.cmp(left_pair))
})
.map(|((first_flag_byte, second_flag_byte), count)| {
SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPair {
first_flag_byte: *first_flag_byte,
first_flag_byte_hex: format!("0x{first_flag_byte:02x}"),
second_flag_byte: *second_flag_byte,
second_flag_byte_hex: format!("0x{second_flag_byte:02x}"),
count: *count,
}
});
let dominant_short_profile_first_flag = short_profile_first_flag_counts
.iter()
.max_by(|(left_byte, left_count), (right_byte, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_byte.cmp(left_byte))
})
.map(|(byte, count)| (*byte, *count));
let dominant_short_profile_second_flag = short_profile_second_flag_counts
.iter()
.max_by(|(left_byte, left_count), (right_byte, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_byte.cmp(left_byte))
})
.map(|(byte, count)| (*byte, *count));
let short_profile_flag_pair_summary = Some(
SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSummary {
row_count_with_0x06_profile_span: short_profile_flag_rows.len(),
unique_flag_pair_count: short_profile_flag_pair_counts.len(),
dominant_first_flag_byte: dominant_short_profile_first_flag.map(|(byte, _)| byte),
dominant_first_flag_byte_hex: dominant_short_profile_first_flag
.map(|(byte, _)| format!("0x{byte:02x}")),
dominant_first_flag_byte_count: dominant_short_profile_first_flag
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_second_flag_byte: dominant_short_profile_second_flag.map(|(byte, _)| byte),
dominant_second_flag_byte_hex: dominant_short_profile_second_flag
.map(|(byte, _)| format!("0x{byte:02x}")),
dominant_second_flag_byte_count: dominant_short_profile_second_flag
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_flag_pair: dominant_short_profile_flag_pair,
sample_rows: short_profile_flag_rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
first_flag_byte,
second_flag_byte,
),
)| {
SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
first_flag_byte: *first_flag_byte,
first_flag_byte_hex: format!("0x{first_flag_byte:02x}"),
second_flag_byte: *second_flag_byte,
second_flag_byte_hex: format!("0x{second_flag_byte:02x}"),
}
},
)
.collect(),
},
);
let classify_side_buffer_mode_family =
|primary_name: Option<&str>, secondary_name: Option<&str>| -> &'static str {
let name = primary_name.or(secondary_name).unwrap_or_default();
if name.starts_with("Bridge") {
"bridge"
} else if name.starts_with("Tunnel") {
"tunnel"
} else if name.starts_with("BallastCap") {
"ballast_cap"
} else if name.starts_with("TrackCap") {
"track_cap"
} else if name.starts_with("Overpass") {
"overpass"
} else if name.is_empty() {
"unknown"
} else {
"other"
}
};
let fixed_policy_rows = payload_envelope_rows
.iter()
.filter(|row| row.policy_chunk_len == Some(0x1a))
.filter_map(|row| {
let embedded_name_row = embedded_name_rows
.iter()
.find(|entry| entry.name_tag_relative_offset == row.name_tag_relative_offset)?;
let policy_tag_relative_offset = row.policy_tag_relative_offset?;
let policy_payload = records_payload
.get(policy_tag_relative_offset + 4..policy_tag_relative_offset + 4 + 0x1a)?;
let first_triplet_dwords = [
read_u32_at(policy_payload, 0)?,
read_u32_at(policy_payload, 4)?,
read_u32_at(policy_payload, 8)?,
];
let second_triplet_dwords = [
read_u32_at(policy_payload, 12)?,
read_u32_at(policy_payload, 16)?,
read_u32_at(policy_payload, 20)?,
];
let trailing_word = read_u16_at(policy_payload, 24)?;
Some((
row.name_tag_relative_offset,
row.primary_name.clone(),
row.secondary_name.clone(),
embedded_name_row.prefix_leading_dword,
embedded_name_row.prefix_trailing_word,
embedded_name_row.prefix_separator_byte,
first_triplet_dwords,
second_triplet_dwords,
trailing_word,
))
})
.collect::<Vec<_>>();
let mut fixed_policy_trailing_word_counts = BTreeMap::<u16, usize>::new();
for (_, _, _, _, _, _, _, _, trailing_word) in &fixed_policy_rows {
*fixed_policy_trailing_word_counts
.entry(*trailing_word)
.or_default() += 1;
}
let dominant_fixed_policy_trailing_word = fixed_policy_trailing_word_counts
.iter()
.max_by(|(left_word, left_count), (right_word, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_word.cmp(left_word))
})
.map(|(word, count)| (*word, *count));
let mut fixed_policy_compact_prefix_groups = BTreeMap::<
(u32, u16, u8),
Vec<(
usize,
Option<String>,
Option<String>,
[u32; 3],
[u32; 3],
u16,
)>,
>::new();
for (
name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
first_triplet_dwords,
second_triplet_dwords,
trailing_word,
) in &fixed_policy_rows
{
fixed_policy_compact_prefix_groups
.entry((
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
))
.or_default()
.push((
*name_tag_relative_offset,
primary_name.clone(),
secondary_name.clone(),
*first_triplet_dwords,
*second_triplet_dwords,
*trailing_word,
));
}
let fixed_policy_compact_prefix_correlations = fixed_policy_compact_prefix_groups
.into_iter()
.map(
|((prefix_leading_dword, prefix_trailing_word, prefix_separator_byte), rows)| {
let mut name_pair_counts =
BTreeMap::<(Option<String>, Option<String>), usize>::new();
let mut mode_family_counts = BTreeMap::<String, usize>::new();
let mut policy_tuple_counts =
BTreeMap::<([u32; 3], [u32; 3], u16), usize>::new();
for (
_name_tag_relative_offset,
primary_name,
secondary_name,
first_triplet_dwords,
second_triplet_dwords,
trailing_word,
) in &rows
{
*name_pair_counts
.entry((primary_name.clone(), secondary_name.clone()))
.or_default() += 1;
*mode_family_counts
.entry(
classify_side_buffer_mode_family(
primary_name.as_deref(),
secondary_name.as_deref(),
)
.to_string(),
)
.or_default() += 1;
*policy_tuple_counts
.entry((
*first_triplet_dwords,
*second_triplet_dwords,
*trailing_word,
))
.or_default() += 1;
}
let dominant_name_pair = name_pair_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|((primary_name, secondary_name), count)| {
(primary_name.clone(), secondary_name.clone(), *count)
});
let dominant_mode_family = mode_family_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(mode_family, count)| (mode_family.clone(), *count));
let dominant_policy_tuple = policy_tuple_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|(
(first_triplet_dwords, second_triplet_dwords, trailing_word),
count,
)| {
(
*first_triplet_dwords,
*second_triplet_dwords,
*trailing_word,
*count,
)
},
);
SmpSavePlacedStructureDynamicSideBufferFixedPolicyCompactPrefixCorrelation {
prefix_leading_dword,
prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
prefix_trailing_word,
prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
prefix_separator_byte,
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
row_count: rows.len(),
unique_policy_tuple_count: policy_tuple_counts.len(),
dominant_primary_name: dominant_name_pair
.as_ref()
.and_then(|(primary_name, _, _)| primary_name.clone()),
dominant_secondary_name: dominant_name_pair
.as_ref()
.and_then(|(_, secondary_name, _)| secondary_name.clone()),
dominant_name_pair_count: dominant_name_pair
.map(|(_, _, count)| count)
.unwrap_or_default(),
dominant_mode_family: dominant_mode_family
.as_ref()
.map(|(mode_family, _)| mode_family.clone()),
dominant_mode_family_count: dominant_mode_family
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_first_triplet_dwords_hex: dominant_policy_tuple
.as_ref()
.map(|(first_triplet_dwords, _, _, _)| {
first_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect()
})
.unwrap_or_default(),
dominant_second_triplet_dwords_hex: dominant_policy_tuple
.as_ref()
.map(|(_, second_triplet_dwords, _, _)| {
second_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect()
})
.unwrap_or_default(),
dominant_trailing_word: dominant_policy_tuple
.map(|(_, _, trailing_word, _)| trailing_word),
dominant_trailing_word_hex: dominant_policy_tuple
.map(|(_, _, trailing_word, _)| format!("0x{trailing_word:04x}")),
dominant_policy_tuple_count: dominant_policy_tuple
.map(|(_, _, _, count)| count)
.unwrap_or_default(),
mode_family_counts: mode_family_counts
.into_iter()
.map(|(mode_family, count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family,
count,
}
})
.collect(),
sample_rows: rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
first_triplet_dwords,
second_triplet_dwords,
trailing_word,
),
)| {
SmpSavePlacedStructureDynamicSideBufferFixedPolicySample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
first_triplet_dwords_hex: first_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect(),
second_triplet_dwords_hex: second_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect(),
trailing_word: *trailing_word,
trailing_word_hex: format!("0x{trailing_word:04x}"),
}
},
)
.collect(),
}
},
)
.take(8)
.collect::<Vec<_>>();
let fixed_policy_summary =
Some(SmpSavePlacedStructureDynamicSideBufferFixedPolicySummary {
row_count_with_0x1a_policy_chunk: fixed_policy_rows.len(),
unique_trailing_word_count: fixed_policy_trailing_word_counts.len(),
dominant_trailing_word: dominant_fixed_policy_trailing_word.map(|(word, _)| word),
dominant_trailing_word_hex: dominant_fixed_policy_trailing_word
.map(|(word, _)| format!("0x{word:04x}")),
dominant_trailing_word_count: dominant_fixed_policy_trailing_word
.map(|(_, count)| count)
.unwrap_or_default(),
compact_prefix_correlations: fixed_policy_compact_prefix_correlations,
sample_rows: fixed_policy_rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
_prefix_leading_dword,
_prefix_trailing_word,
_prefix_separator_byte,
first_triplet_dwords,
second_triplet_dwords,
trailing_word,
),
)| {
SmpSavePlacedStructureDynamicSideBufferFixedPolicySample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
first_triplet_dwords_hex: first_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect(),
second_triplet_dwords_hex: second_triplet_dwords
.iter()
.map(|value| format!("0x{value:08x}"))
.collect(),
trailing_word: *trailing_word,
trailing_word_hex: format!("0x{trailing_word:04x}"),
}
},
)
.collect(),
});
let name_prelude_candidate_rows = embedded_name_rows
.iter()
.enumerate()
.filter_map(|(row_index, row)| {
let candidate_offset = row.name_tag_relative_offset.checked_sub(3)?;
let child_count_candidate = read_u16_at(records_payload, candidate_offset)?;
let saved_primary_child_byte_candidate =
read_u8_at(records_payload, candidate_offset + 2)?;
Some((
row.name_tag_relative_offset,
row.primary_name.clone(),
row.secondary_name.clone(),
row.prefix_leading_dword,
row.prefix_trailing_word,
row.prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
row_index.checked_sub(1).and_then(|previous_index| {
payload_envelope_rows
.get(previous_index)
.and_then(|row| row.profile_chunk_len_to_next_name_or_end)
}),
row_index.checked_sub(1).and_then(|previous_index| {
payload_envelope_rows.get(previous_index).and_then(|row| {
row.short_profile_first_flag_byte
.zip(row.short_profile_second_flag_byte)
})
}),
))
})
.collect::<Vec<_>>();
let mut name_prelude_candidate_pattern_counts = BTreeMap::<(u16, u8), usize>::new();
let mut name_prelude_child_count_counts = BTreeMap::<u16, usize>::new();
let mut name_prelude_saved_primary_counts = BTreeMap::<u8, usize>::new();
for (_, _, _, _, _, _, child_count_candidate, saved_primary_child_byte_candidate, _, _) in
&name_prelude_candidate_rows
{
*name_prelude_candidate_pattern_counts
.entry((*child_count_candidate, *saved_primary_child_byte_candidate))
.or_default() += 1;
*name_prelude_child_count_counts
.entry(*child_count_candidate)
.or_default() += 1;
*name_prelude_saved_primary_counts
.entry(*saved_primary_child_byte_candidate)
.or_default() += 1;
}
let dominant_name_prelude_candidate_pattern = name_prelude_candidate_pattern_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|((child_count_candidate, saved_primary_child_byte_candidate), count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!("0x{child_count_candidate:04x}"),
saved_primary_child_byte_candidate: *saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
count: *count,
}
},
);
let dominant_name_prelude_child_count = name_prelude_child_count_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let dominant_name_prelude_saved_primary = name_prelude_saved_primary_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let mut name_prelude_pattern_groups = BTreeMap::<
(u16, u8),
Vec<(usize, Option<String>, Option<String>, Option<usize>)>,
>::new();
for (
name_tag_relative_offset,
primary_name,
secondary_name,
_prefix_leading_dword,
_prefix_trailing_word,
_prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_span,
_previous_short_profile_flag_pair,
) in &name_prelude_candidate_rows
{
name_prelude_pattern_groups
.entry((*child_count_candidate, *saved_primary_child_byte_candidate))
.or_default()
.push((
*name_tag_relative_offset,
primary_name.clone(),
secondary_name.clone(),
*previous_span,
));
}
let candidate_pattern_correlations = name_prelude_pattern_groups
.into_iter()
.map(
|(
(child_count_candidate, saved_primary_child_byte_candidate),
rows,
)| {
let mut name_pair_counts =
BTreeMap::<(Option<String>, Option<String>), usize>::new();
let mut profile_span_counts = BTreeMap::<usize, usize>::new();
let mut mode_family_counts = BTreeMap::<String, usize>::new();
for (_, primary_name, secondary_name, previous_span) in &rows {
*name_pair_counts
.entry((primary_name.clone(), secondary_name.clone()))
.or_default() += 1;
*mode_family_counts
.entry(
classify_side_buffer_mode_family(
primary_name.as_deref(),
secondary_name.as_deref(),
)
.to_string(),
)
.or_default() += 1;
if let Some(previous_span) = previous_span {
*profile_span_counts.entry(*previous_span).or_default() += 1;
}
}
let dominant_name_pair = name_pair_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|((primary_name, secondary_name), count)| {
(primary_name.clone(), secondary_name.clone(), *count)
});
let dominant_profile_span = profile_span_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(span, count)| (*span, *count));
let dominant_mode_family = mode_family_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(mode_family, count)| (mode_family.clone(), *count));
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePatternCorrelation {
child_count_candidate,
child_count_candidate_hex: format!("0x{child_count_candidate:04x}"),
saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
row_count: rows.len(),
unique_name_pair_count: name_pair_counts.len(),
unique_profile_span_count: profile_span_counts.len(),
dominant_primary_name: dominant_name_pair
.as_ref()
.and_then(|(primary_name, _, _)| primary_name.clone()),
dominant_secondary_name: dominant_name_pair
.as_ref()
.and_then(|(_, secondary_name, _)| secondary_name.clone()),
dominant_name_pair_count: dominant_name_pair
.map(|(_, _, count)| count)
.unwrap_or_default(),
dominant_profile_span: dominant_profile_span
.map(|(profile_span, _)| profile_span),
dominant_profile_span_count: dominant_profile_span
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_mode_family: dominant_mode_family
.as_ref()
.map(|(mode_family, _)| mode_family.clone()),
dominant_mode_family_count: dominant_mode_family
.map(|(_, count)| count)
.unwrap_or_default(),
mode_family_counts: mode_family_counts
.into_iter()
.map(|(mode_family, count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family,
count,
}
})
.collect(),
sample_rows: rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
previous_profile_chunk_len_to_next_name_or_end,
),
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
previous_profile_chunk_len_to_next_name_or_end:
*previous_profile_chunk_len_to_next_name_or_end,
}
},
)
.collect(),
}
},
)
.take(8)
.collect::<Vec<_>>();
let mut name_prelude_profile_span_groups = BTreeMap::<
usize,
Vec<(usize, Option<String>, Option<String>, u32, u16, u8, u16, u8)>,
>::new();
for (
name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_span,
_previous_short_profile_flag_pair,
) in &name_prelude_candidate_rows
{
if let Some(previous_span) = previous_span {
name_prelude_profile_span_groups
.entry(*previous_span)
.or_default()
.push((
*name_tag_relative_offset,
primary_name.clone(),
secondary_name.clone(),
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
*child_count_candidate,
*saved_primary_child_byte_candidate,
));
}
}
let profile_span_correlations = name_prelude_profile_span_groups
.into_iter()
.map(|(previous_profile_chunk_len_to_next_name_or_end, rows)| {
let mut pattern_counts = BTreeMap::<(u16, u8), usize>::new();
let mut child_count_counts = BTreeMap::<u16, usize>::new();
let mut saved_primary_counts = BTreeMap::<u8, usize>::new();
let mut mode_family_counts = BTreeMap::<String, usize>::new();
let mut prefix_counts = BTreeMap::<(u32, u16, u8), usize>::new();
for (
_name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
) in &rows
{
*pattern_counts
.entry((*child_count_candidate, *saved_primary_child_byte_candidate))
.or_default() += 1;
*child_count_counts
.entry(*child_count_candidate)
.or_default() += 1;
*saved_primary_counts
.entry(*saved_primary_child_byte_candidate)
.or_default() += 1;
*prefix_counts
.entry((
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
))
.or_default() += 1;
*mode_family_counts
.entry(
classify_side_buffer_mode_family(
primary_name.as_deref(),
secondary_name.as_deref(),
)
.to_string(),
)
.or_default() += 1;
}
let dominant_pattern = pattern_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|((child_count_candidate, saved_primary_child_byte_candidate), count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!("0x{child_count_candidate:04x}"),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
count: *count,
}
},
);
let dominant_child_count = child_count_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let dominant_saved_primary = saved_primary_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let dominant_mode_family = mode_family_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(mode_family, count)| (mode_family.clone(), *count));
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
previous_profile_chunk_len_to_next_name_or_end,
row_count: rows.len(),
dominant_child_count_candidate: dominant_child_count.map(|(value, _)| value),
dominant_child_count_candidate_count: dominant_child_count
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_saved_primary_child_byte_candidate: dominant_saved_primary
.map(|(value, _)| value),
dominant_saved_primary_child_byte_candidate_hex: dominant_saved_primary
.map(|(value, _)| format!("0x{value:02x}")),
dominant_saved_primary_child_byte_candidate_count: dominant_saved_primary
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_candidate_pattern: dominant_pattern,
dominant_mode_family: dominant_mode_family
.as_ref()
.map(|(mode_family, _)| mode_family.clone()),
dominant_mode_family_count: dominant_mode_family
.map(|(_, count)| count)
.unwrap_or_default(),
mode_family_counts: mode_family_counts
.into_iter()
.map(|(mode_family, count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family,
count,
}
})
.collect(),
compact_prefix_pattern_summaries: prefix_counts
.into_iter()
.map(
|(
(prefix_leading_dword, prefix_trailing_word, prefix_separator_byte),
count,
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
prefix_leading_dword,
prefix_leading_dword_hex: format!(
"0x{prefix_leading_dword:08x}"
),
prefix_trailing_word,
prefix_trailing_word_hex: format!(
"0x{prefix_trailing_word:04x}"
),
prefix_separator_byte,
prefix_separator_byte_hex: format!(
"0x{prefix_separator_byte:02x}"
),
count,
}
},
)
.collect(),
sample_rows: rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
),
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
prefix_leading_dword: *prefix_leading_dword,
prefix_leading_dword_hex: format!(
"0x{prefix_leading_dword:08x}"
),
prefix_trailing_word: *prefix_trailing_word,
prefix_trailing_word_hex: format!(
"0x{prefix_trailing_word:04x}"
),
prefix_separator_byte: *prefix_separator_byte,
prefix_separator_byte_hex: format!(
"0x{prefix_separator_byte:02x}"
),
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
}
},
)
.collect(),
}
})
.take(8)
.collect::<Vec<_>>();
let mut name_prelude_compact_prefix_groups = BTreeMap::<
(u32, u16, u8),
Vec<(
usize,
Option<String>,
Option<String>,
u16,
u8,
Option<usize>,
Option<(u8, u8)>,
)>,
>::new();
for (
name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_span,
previous_short_profile_flag_pair,
) in &name_prelude_candidate_rows
{
name_prelude_compact_prefix_groups
.entry((
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
))
.or_default()
.push((
*name_tag_relative_offset,
primary_name.clone(),
secondary_name.clone(),
*child_count_candidate,
*saved_primary_child_byte_candidate,
*previous_span,
*previous_short_profile_flag_pair,
));
}
let compact_prefix_correlations = name_prelude_compact_prefix_groups
.into_iter()
.map(
|(
(prefix_leading_dword, prefix_trailing_word, prefix_separator_byte),
rows,
)| {
let mut name_pair_counts =
BTreeMap::<(Option<String>, Option<String>), usize>::new();
let mut profile_span_counts = BTreeMap::<usize, usize>::new();
let mut candidate_pattern_counts = BTreeMap::<(u16, u8), usize>::new();
let mut mode_family_counts = BTreeMap::<String, usize>::new();
let mut flag_pair_counts = BTreeMap::<(u8, u8), usize>::new();
for (
_name_tag_relative_offset,
primary_name,
secondary_name,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_span,
previous_short_profile_flag_pair,
) in &rows
{
*name_pair_counts
.entry((primary_name.clone(), secondary_name.clone()))
.or_default() += 1;
if let Some(previous_span) = previous_span {
*profile_span_counts.entry(*previous_span).or_default() += 1;
}
*candidate_pattern_counts
.entry((*child_count_candidate, *saved_primary_child_byte_candidate))
.or_default() += 1;
*mode_family_counts
.entry(
classify_side_buffer_mode_family(
primary_name.as_deref(),
secondary_name.as_deref(),
)
.to_string(),
)
.or_default() += 1;
if let Some((first_flag_byte, second_flag_byte)) =
previous_short_profile_flag_pair
{
*flag_pair_counts
.entry((*first_flag_byte, *second_flag_byte))
.or_default() += 1;
}
}
let dominant_name_pair = name_pair_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|((primary_name, secondary_name), count)| {
(primary_name.clone(), secondary_name.clone(), *count)
});
let dominant_profile_span = profile_span_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(span, count)| (*span, *count));
let dominant_candidate_pattern = candidate_pattern_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|(
(child_count_candidate, saved_primary_child_byte_candidate),
count,
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
count: *count,
}
},
);
let dominant_mode_family = mode_family_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(mode_family, count)| (mode_family.clone(), *count));
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation {
prefix_leading_dword,
prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
prefix_trailing_word,
prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
prefix_separator_byte,
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
row_count: rows.len(),
unique_name_pair_count: name_pair_counts.len(),
unique_profile_span_count: profile_span_counts.len(),
dominant_primary_name: dominant_name_pair
.as_ref()
.and_then(|(primary_name, _, _)| primary_name.clone()),
dominant_secondary_name: dominant_name_pair
.as_ref()
.and_then(|(_, secondary_name, _)| secondary_name.clone()),
dominant_name_pair_count: dominant_name_pair
.map(|(_, _, count)| count)
.unwrap_or_default(),
dominant_profile_span: dominant_profile_span
.map(|(profile_span, _)| profile_span),
dominant_profile_span_count: dominant_profile_span
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_candidate_pattern,
dominant_mode_family: dominant_mode_family
.as_ref()
.map(|(mode_family, _)| mode_family.clone()),
dominant_mode_family_count: dominant_mode_family
.map(|(_, count)| count)
.unwrap_or_default(),
mode_family_counts: mode_family_counts
.into_iter()
.map(|(mode_family, count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family,
count,
}
})
.collect(),
name_pair_summaries: name_pair_counts
.into_iter()
.map(|((primary_name, secondary_name), count)| {
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name,
secondary_name,
count,
}
})
.collect(),
profile_span_counts: profile_span_counts
.into_iter()
.map(
|(previous_profile_chunk_len_to_next_name_or_end, count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount {
previous_profile_chunk_len_to_next_name_or_end,
count,
}
},
)
.collect(),
rows_with_previous_short_profile_flag_pair: flag_pair_counts
.values()
.copied()
.sum(),
previous_short_profile_flag_pair_counts: flag_pair_counts
.into_iter()
.map(|((first_flag_byte, second_flag_byte), count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount {
first_flag_byte,
first_flag_byte_hex: format!("0x{first_flag_byte:02x}"),
second_flag_byte,
second_flag_byte_hex: format!("0x{second_flag_byte:02x}"),
count,
}
})
.collect(),
sample_rows: rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_profile_chunk_len_to_next_name_or_end,
_previous_short_profile_flag_pair,
),
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
previous_profile_chunk_len_to_next_name_or_end:
*previous_profile_chunk_len_to_next_name_or_end,
}
},
)
.collect(),
}
},
)
.take(8)
.collect::<Vec<_>>();
let name_prelude_candidate_summary = Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSummary {
row_count_with_candidate_window: name_prelude_candidate_rows.len(),
unique_candidate_pattern_count: name_prelude_candidate_pattern_counts.len(),
dominant_child_count_candidate: dominant_name_prelude_child_count
.map(|(value, _)| value),
dominant_child_count_candidate_count: dominant_name_prelude_child_count
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_saved_primary_child_byte_candidate: dominant_name_prelude_saved_primary
.map(|(value, _)| value),
dominant_saved_primary_child_byte_candidate_hex:
dominant_name_prelude_saved_primary.map(|(value, _)| format!("0x{value:02x}")),
dominant_saved_primary_child_byte_candidate_count:
dominant_name_prelude_saved_primary
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_candidate_pattern: dominant_name_prelude_candidate_pattern.clone(),
candidate_pattern_correlations,
profile_span_correlations,
compact_prefix_correlations,
sample_rows: name_prelude_candidate_rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
_prefix_leading_dword,
_prefix_trailing_word,
_prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
previous_profile_chunk_len_to_next_name_or_end,
_previous_short_profile_flag_pair,
),
)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!("0x{child_count_candidate:04x}"),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
previous_profile_chunk_len_to_next_name_or_end:
*previous_profile_chunk_len_to_next_name_or_end,
}
},
)
.collect(),
},
);
let dominant_profile_span_class_summary = dominant_profile_chunk_len
.map(|(dominant_profile_span_len, _)| {
let dominant_rows = embedded_name_rows
.iter()
.zip(payload_envelope_rows.iter())
.filter_map(|(name_row, envelope_row)| {
(envelope_row.profile_chunk_len_to_next_name_or_end
== Some(dominant_profile_span_len))
.then(|| {
let candidate_offset =
name_row.name_tag_relative_offset.checked_sub(3);
let child_count_candidate = candidate_offset
.and_then(|offset| read_u16_at(records_payload, offset));
let saved_primary_child_byte_candidate = candidate_offset
.and_then(|offset| read_u8_at(records_payload, offset + 2));
(
name_row.name_tag_relative_offset,
name_row.primary_name.clone(),
name_row.secondary_name.clone(),
name_row.prefix_leading_dword,
name_row.prefix_trailing_word,
name_row.prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
)
})
})
.collect::<Vec<_>>();
let mut dominant_name_pair_counts =
BTreeMap::<(Option<String>, Option<String>), usize>::new();
let mut dominant_prefix_counts = BTreeMap::<(u32, u16, u8), usize>::new();
let mut dominant_candidate_pattern_counts = BTreeMap::<(u16, u8), usize>::new();
for (
_,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
) in &dominant_rows
{
*dominant_name_pair_counts
.entry((primary_name.clone(), secondary_name.clone()))
.or_default() += 1;
*dominant_prefix_counts
.entry((
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
))
.or_default() += 1;
if let (Some(child_count_candidate), Some(saved_primary_child_byte_candidate)) =
(child_count_candidate, saved_primary_child_byte_candidate)
{
*dominant_candidate_pattern_counts
.entry((*child_count_candidate, *saved_primary_child_byte_candidate))
.or_default() += 1;
}
}
let dominant_name_pair = dominant_name_pair_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|((primary_name, secondary_name), count)| {
(primary_name.clone(), secondary_name.clone(), *count)
});
let dominant_prefix = dominant_prefix_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|((prefix_leading_dword, prefix_trailing_word, prefix_separator_byte), count)| {
(
*prefix_leading_dword,
*prefix_trailing_word,
*prefix_separator_byte,
*count,
)
},
);
let dominant_candidate_pattern = dominant_candidate_pattern_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(
|((child_count_candidate, saved_primary_child_byte_candidate), count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
count: *count,
}
},
);
let name_pair_summaries = dominant_name_pair_counts
.iter()
.map(|((primary_name, secondary_name), count)| {
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
count: *count,
}
})
.take(8)
.collect::<Vec<_>>();
let compact_prefix_pattern_summaries = dominant_prefix_counts
.iter()
.map(
|((prefix_leading_dword, prefix_trailing_word, prefix_separator_byte), count)| {
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanPrefixSummary {
prefix_leading_dword: *prefix_leading_dword,
prefix_leading_dword_hex: format!(
"0x{prefix_leading_dword:08x}"
),
prefix_trailing_word: *prefix_trailing_word,
prefix_trailing_word_hex: format!(
"0x{prefix_trailing_word:04x}"
),
prefix_separator_byte: *prefix_separator_byte,
prefix_separator_byte_hex: format!(
"0x{prefix_separator_byte:02x}"
),
count: *count,
}
},
)
.take(8)
.collect::<Vec<_>>();
let candidate_pattern_summaries = dominant_candidate_pattern_counts
.iter()
.map(
|((child_count_candidate, saved_primary_child_byte_candidate), count)| {
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: format!(
"0x{child_count_candidate:04x}"
),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex: format!(
"0x{saved_primary_child_byte_candidate:02x}"
),
count: *count,
}
},
)
.take(8)
.collect::<Vec<_>>();
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanClassSummary {
profile_chunk_len_to_next_name_or_end: dominant_profile_span_len,
row_count: dominant_rows.len(),
unique_name_pair_count: dominant_name_pair_counts.len(),
unique_compact_prefix_pattern_count: dominant_prefix_counts.len(),
dominant_candidate_pattern,
dominant_primary_name: dominant_name_pair
.as_ref()
.and_then(|(primary_name, _, _)| primary_name.clone()),
dominant_secondary_name: dominant_name_pair
.as_ref()
.and_then(|(_, secondary_name, _)| secondary_name.clone()),
dominant_name_pair_count: dominant_name_pair
.map(|(_, _, count)| count)
.unwrap_or_default(),
dominant_prefix_leading_dword: dominant_prefix
.map(|(prefix_leading_dword, _, _, _)| prefix_leading_dword),
dominant_prefix_leading_dword_hex: dominant_prefix.map(
|(prefix_leading_dword, _, _, _)| format!("0x{prefix_leading_dword:08x}"),
),
dominant_prefix_trailing_word: dominant_prefix
.map(|(_, prefix_trailing_word, _, _)| prefix_trailing_word),
dominant_prefix_trailing_word_hex: dominant_prefix.map(
|(_, prefix_trailing_word, _, _)| format!("0x{prefix_trailing_word:04x}"),
),
dominant_prefix_separator_byte: dominant_prefix
.map(|(_, _, prefix_separator_byte, _)| prefix_separator_byte),
dominant_prefix_separator_byte_hex: dominant_prefix.map(
|(_, _, prefix_separator_byte, _)| format!("0x{prefix_separator_byte:02x}"),
),
dominant_prefix_count: dominant_prefix
.map(|(_, _, _, count)| count)
.unwrap_or_default(),
sample_rows: dominant_rows
.iter()
.take(8)
.enumerate()
.map(
|(
sample_index,
(
name_tag_relative_offset,
primary_name,
secondary_name,
prefix_leading_dword,
prefix_trailing_word,
prefix_separator_byte,
child_count_candidate,
saved_primary_child_byte_candidate,
),
)| {
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanSample {
sample_index,
name_tag_relative_offset: *name_tag_relative_offset,
primary_name: primary_name.clone(),
secondary_name: secondary_name.clone(),
prefix_leading_dword: *prefix_leading_dword,
prefix_leading_dword_hex: format!(
"0x{prefix_leading_dword:08x}"
),
prefix_trailing_word: *prefix_trailing_word,
prefix_trailing_word_hex: format!(
"0x{prefix_trailing_word:04x}"
),
prefix_separator_byte: *prefix_separator_byte,
prefix_separator_byte_hex: format!(
"0x{prefix_separator_byte:02x}"
),
child_count_candidate: *child_count_candidate,
child_count_candidate_hex: child_count_candidate
.map(|value| format!("0x{value:04x}")),
saved_primary_child_byte_candidate:
*saved_primary_child_byte_candidate,
saved_primary_child_byte_candidate_hex:
saved_primary_child_byte_candidate
.map(|value| format!("0x{value:02x}")),
}
},
)
.collect(),
name_pair_summaries,
compact_prefix_pattern_summaries,
candidate_pattern_summaries,
}
});
let payload_envelope_summary = Some(
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
row_count_with_policy_tag_before_next_name,
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
row_count_missing_policy_tag_before_next_name,
row_count_missing_profile_tag_after_policy,
unique_policy_chunk_lens,
unique_profile_chunk_lens,
dominant_policy_chunk_len: dominant_policy_chunk_len.map(|(len, _)| len),
dominant_policy_chunk_len_count: dominant_policy_chunk_len
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_profile_chunk_len: dominant_profile_chunk_len.map(|(len, _)| len),
dominant_profile_chunk_len_count: dominant_profile_chunk_len
.map(|(_, count)| count)
.unwrap_or_default(),
short_profile_flag_pair_summary: short_profile_flag_pair_summary.clone(),
fixed_policy_summary: fixed_policy_summary.clone(),
name_prelude_candidate_summary: name_prelude_candidate_summary.clone(),
dominant_profile_span_class_summary: dominant_profile_span_class_summary.clone(),
sample_rows: payload_envelope_rows
.iter()
.take(8)
.enumerate()
.map(|(sample_index, row)| {
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample {
sample_index,
name_tag_relative_offset: row.name_tag_relative_offset,
primary_name: row.primary_name.clone(),
secondary_name: row.secondary_name.clone(),
name_payload_end_relative_offset: row.name_payload_end_relative_offset,
policy_tag_relative_offset: row.policy_tag_relative_offset,
profile_tag_relative_offset: row.profile_tag_relative_offset,
next_name_tag_relative_offset: row.next_name_tag_relative_offset,
name_to_policy_gap_len: row.name_to_policy_gap_len,
policy_chunk_len: row.policy_chunk_len,
profile_chunk_len_to_next_name_or_end: row
.profile_chunk_len_to_next_name_or_end,
}
})
.collect(),
},
);
let bitset_len = ((usize::try_from(summary.live_id_bound).ok()?).saturating_add(8)) / 8;
let live_entry_prelude_summary = payload
.get(
INDEXED_COLLECTION_SERIALIZED_HEADER_LEN
..INDEXED_COLLECTION_SERIALIZED_HEADER_LEN + bitset_len,
)
.and_then(|bitset| {
let live_entry_ids =
decode_live_entry_ids_from_tombstone_bitset(bitset, summary.live_id_bound)?;
if live_entry_ids.len() != usize::try_from(summary.live_record_count).ok()? {
return None;
}
#[derive(Clone)]
struct LiveEntryPreludeRow {
live_entry_id: u32,
payload_relative_offset: usize,
child_count: u16,
saved_primary_child_byte: u8,
first_payload_dword: u32,
first_name_tag_relative_offset: Option<usize>,
first_primary_name: Option<String>,
first_secondary_name: Option<String>,
first_tertiary_name: Option<String>,
}
let mut rows = Vec::new();
let mut cursor = 0usize;
for live_entry_id in live_entry_ids.iter().copied() {
let payload_len = usize::from(read_u16_at(records_payload, cursor)?);
let payload_relative_offset = cursor.checked_add(2)?;
let payload_end = payload_relative_offset.checked_add(payload_len)?;
let payload_bytes =
records_payload.get(payload_relative_offset..payload_end)?;
let child_count = read_u16_at(payload_bytes, 0)?;
let saved_primary_child_byte = read_u8_at(payload_bytes, 2)?;
let first_payload_dword = read_u32_at(payload_bytes, 0)?;
let first_name_tag_relative_offset = (0usize..=16usize).find(|offset| {
read_u16_at(payload_bytes, *offset) == Some(SAVE_REGION_RECORD_NAME_TAG)
});
let (first_primary_name, first_secondary_name, first_tertiary_name) =
first_name_tag_relative_offset
.and_then(|relative_offset| {
let name_payload =
payload_bytes.get(relative_offset.checked_add(4)?..)?;
parse_save_len_prefixed_ascii_name_triplet(name_payload)
})
.unwrap_or_default();
rows.push(LiveEntryPreludeRow {
live_entry_id,
payload_relative_offset,
child_count,
saved_primary_child_byte,
first_payload_dword,
first_name_tag_relative_offset,
first_primary_name: (!first_primary_name.is_empty())
.then_some(first_primary_name),
first_secondary_name: (!first_secondary_name.is_empty())
.then_some(first_secondary_name),
first_tertiary_name,
});
cursor = payload_end;
}
let payload_relative_offset_monotonic = rows.windows(2).all(|window| {
window[0].payload_relative_offset < window[1].payload_relative_offset
});
let mut child_count_counts = BTreeMap::<u16, usize>::new();
let mut saved_primary_child_byte_counts = BTreeMap::<u8, usize>::new();
let mut first_name_tag_relative_offset_counts = BTreeMap::<usize, usize>::new();
for row in &rows {
*child_count_counts.entry(row.child_count).or_default() += 1;
*saved_primary_child_byte_counts
.entry(row.saved_primary_child_byte)
.or_default() += 1;
if let Some(first_name_tag_relative_offset) = row.first_name_tag_relative_offset
{
*first_name_tag_relative_offset_counts
.entry(first_name_tag_relative_offset)
.or_default() += 1;
}
}
let dominant_child_count = child_count_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let dominant_saved_primary_child_byte = saved_primary_child_byte_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
let dominant_first_name_tag_relative_offset = first_name_tag_relative_offset_counts
.iter()
.max_by(|(left_key, left_count), (right_key, right_count)| {
left_count
.cmp(right_count)
.then_with(|| right_key.cmp(left_key))
})
.map(|(value, count)| (*value, *count));
Some(
SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSummary {
live_entry_directory_row_count: rows.len(),
decoded_live_entry_id_count: live_entry_ids.len(),
payload_relative_offset_monotonic,
rows_with_payload_pointer_inside_records_span: rows.len(),
rows_with_zero_child_count: rows
.iter()
.filter(|row| row.child_count == 0)
.count(),
rows_with_nonzero_child_count: rows
.iter()
.filter(|row| row.child_count != 0)
.count(),
rows_with_first_name_tag_after_prelude: rows
.iter()
.filter(|row| row.first_name_tag_relative_offset.is_some())
.count(),
rows_with_first_name_tag_at_offset_3: rows
.iter()
.filter(|row| row.first_name_tag_relative_offset == Some(3))
.count(),
unique_child_count_values: child_count_counts.keys().copied().collect(),
unique_first_name_tag_relative_offsets:
first_name_tag_relative_offset_counts
.keys()
.copied()
.collect(),
dominant_child_count: dominant_child_count.map(|(value, _)| value),
dominant_child_count_count: dominant_child_count
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_saved_primary_child_byte: dominant_saved_primary_child_byte
.map(|(value, _)| value),
dominant_saved_primary_child_byte_hex: dominant_saved_primary_child_byte
.map(|(value, _)| format!("0x{value:02x}")),
dominant_saved_primary_child_byte_count: dominant_saved_primary_child_byte
.map(|(_, count)| count)
.unwrap_or_default(),
dominant_first_name_tag_relative_offset:
dominant_first_name_tag_relative_offset.map(|(value, _)| value),
dominant_first_name_tag_relative_offset_count:
dominant_first_name_tag_relative_offset
.map(|(_, count)| count)
.unwrap_or_default(),
sample_rows: rows
.iter()
.take(8)
.enumerate()
.map(|(sample_index, row)| {
SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSample {
sample_index,
live_entry_id: row.live_entry_id,
payload_relative_offset: row.payload_relative_offset as u32,
payload_relative_offset_hex: format!(
"0x{:08x}",
row.payload_relative_offset
),
payload_relative_to_records: row.payload_relative_offset,
child_count: row.child_count,
child_count_hex: format!("0x{:04x}", row.child_count),
saved_primary_child_byte: row.saved_primary_child_byte,
saved_primary_child_byte_hex: format!(
"0x{:02x}",
row.saved_primary_child_byte
),
first_payload_dword_hex: format!(
"0x{:08x}",
row.first_payload_dword
),
first_name_tag_relative_offset: row
.first_name_tag_relative_offset,
first_primary_name: row.first_primary_name.clone(),
first_secondary_name: row.first_secondary_name.clone(),
first_tertiary_name: row.first_tertiary_name.clone(),
}
})
.collect(),
},
)
});
let unique_embedded_name_pair_count = name_pair_summaries.len();
let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
let decoded_embedded_name_row_count = embedded_name_rows
.iter()
.filter(|row| row.primary_name.is_some() && row.secondary_name.is_some())
.count();
let decoded_embedded_name_row_with_tertiary_name_count = embedded_name_rows
.iter()
.filter(|row| {
row.primary_name.is_some()
&& row.secondary_name.is_some()
&& row.tertiary_name.is_some()
})
.count();
return Some(SmpSavePlacedStructureDynamicSideBufferProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
semantic_family: "scenario-save-placed-structure-dynamic-side-buffer-records".to_string(),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
records_span_len: close_tag_offset.saturating_sub(records_tag_offset + 4),
direct_record_stride: summary.direct_record_stride,
direct_record_stride_hex: format!("0x{:08x}", summary.direct_record_stride),
live_id_bound: summary.live_id_bound,
live_id_bound_hex: format!("0x{:08x}", summary.live_id_bound),
live_record_count: summary.live_record_count,
live_record_count_hex: format!("0x{:08x}", summary.live_record_count),
owner_shared_dword,
owner_shared_dword_hex: format!("0x{owner_shared_dword:08x}"),
owner_shared_dword_relative_offset,
owner_shared_dword_matches_first_compact_prefix_leading_dword:
owner_shared_dword == prefix_leading_dword,
first_record_child_count_after_owner_shared,
first_record_child_count_after_owner_shared_hex: first_record_child_count_after_owner_shared
.map(|value| format!("0x{value:04x}")),
first_record_saved_primary_child_byte_after_owner_shared,
first_record_saved_primary_child_byte_after_owner_shared_hex:
first_record_saved_primary_child_byte_after_owner_shared
.map(|value| format!("0x{value:02x}")),
first_record_first_name_tag_relative_offset_after_owner_shared,
prefix_leading_dword,
prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
prefix_trailing_word,
prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
prefix_separator_byte,
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
first_embedded_name_tag_relative_offset,
embedded_name_tag_count: embedded_name_tag_offsets.len(),
decoded_embedded_name_row_count,
decoded_embedded_name_row_with_tertiary_name_count,
unique_compact_prefix_pattern_count: compact_prefix_pattern_summaries.len(),
prefix_leading_dword_matching_embedded_profile_tag_count,
unique_embedded_name_pair_count,
first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
first_embedded_tertiary_name: first_embedded_tertiary_name.clone(),
embedded_name_row_samples,
compact_prefix_pattern_summaries,
name_pair_summaries,
payload_envelope_summary,
live_entry_prelude_summary: live_entry_prelude_summary.clone(),
evidence: vec![
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
format!(
"direct disassembly now shows 0x00493be0 consuming shared owner-local dword 0x{owner_shared_dword:08x} from the 0x38a6 stream before iterating live infrastructure records"
),
format!(
"grounded 0x38a6 record stream then starts the first infrastructure payload with child_count={}, saved_primary_child_byte={}, and first 0x55f1 at relative offset {:?} after that shared dword",
first_record_child_count_after_owner_shared.unwrap_or_default(),
first_record_saved_primary_child_byte_after_owner_shared
.map(|value| format!("0x{value:02x}"))
.as_deref()
.unwrap_or("0x00"),
first_record_first_name_tag_relative_offset_after_owner_shared
),
"records payload begins with a compact 6-byte prefix plus one separator byte before the first embedded 0x55f1 name row".to_string(),
"first embedded 0x55f1 row decodes with placed-structure-style dual names, which makes this the strongest current candidate for the separate placed-structure dynamic side-buffer owner seam".to_string(),
format!(
"grounded first embedded names are {:?}/{:?}/{:?} with {} embedded 0x55f1 name rows in the tagged records span",
Some(first_embedded_primary_name),
Some(first_embedded_secondary_name),
first_embedded_tertiary_name,
embedded_name_tag_offsets.len()
),
format!(
"{} of {} embedded name rows use compact leading dword 0x{:08x}, matching the placed-structure embedded profile tag",
prefix_leading_dword_matching_embedded_profile_tag_count,
embedded_name_rows.len(),
u32::from(SAVE_REGION_RECORD_PROFILE_TAG)
),
format!(
"{decoded_embedded_name_row_count} decoded embedded name rows collapse into {} unique placed-structure name pairs; {} rows also expose a third embedded 0x55f1 string",
unique_embedded_name_pair_count
,
decoded_embedded_name_row_with_tertiary_name_count
),
format!(
"{} of {} embedded 0x55f1 rows currently have a complete 0x55f1/0x55f2/0x55f3 envelope before the next name row; {} rows are still missing 0x55f2 and {} rows have 0x55f2 without a later 0x55f3",
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
embedded_name_rows.len(),
row_count_missing_policy_tag_before_next_name,
row_count_missing_profile_tag_after_policy
),
dominant_policy_chunk_len
.map(|(policy_chunk_len, count)| {
format!(
"dominant embedded 0x55f2 policy chunk length is 0x{policy_chunk_len:x} bytes across {count} rows"
)
})
.unwrap_or_else(|| {
"no dominant embedded 0x55f2 policy chunk length was available"
.to_string()
}),
dominant_profile_chunk_len
.map(|(profile_chunk_len, count)| {
format!(
"dominant embedded 0x55f3 payload-to-next-name span is 0x{profile_chunk_len:x} bytes across {count} rows"
)
})
.unwrap_or_else(|| {
"no dominant embedded 0x55f3 payload-to-next-name span was available"
.to_string()
}),
short_profile_flag_pair_summary
.as_ref()
.and_then(|summary| summary.dominant_flag_pair.as_ref())
.map(|pair| {
format!(
"direct disassembly now bounds the short trailing lane through 0x52ebd0/0x52ec50 as two serialized flag bytes folded into [this+0x20] bits 0x20/0x40; grounded 0x06-byte rows currently favor {}/{} across {} rows ({} rows total with the short span)",
pair.first_flag_byte_hex,
pair.second_flag_byte_hex,
pair.count,
short_profile_flag_pair_summary
.as_ref()
.map(|summary| summary.row_count_with_0x06_profile_span)
.unwrap_or_default()
)
})
.unwrap_or_else(|| {
"no dominant short trailing flag-byte pair was available".to_string()
}),
fixed_policy_summary
.as_ref()
.map(|summary| {
format!(
"direct disassembly now bounds the fixed 0x55f2 lane through 0x455870/0x455930 as six serialized dwords plus one trailing u16; grounded rows currently keep trailing word {} across {} of {} fixed-policy rows",
summary
.dominant_trailing_word_hex
.as_deref()
.unwrap_or("0x0000"),
summary.dominant_trailing_word_count,
summary.row_count_with_0x1a_policy_chunk
)
})
.unwrap_or_else(|| {
"no fixed 0x55f2 policy summary was available".to_string()
}),
live_entry_prelude_summary
.as_ref()
.map(|summary| {
format!(
"decoded {} live-entry directory rows with payload pointers inside the records span; dominant child count={} x{}, dominant saved primary-child byte={} x{}, dominant first 0x55f1 offset={} x{}, and {} rows start the first child callback immediately at payload +0x3",
summary.rows_with_payload_pointer_inside_records_span,
summary.dominant_child_count.unwrap_or_default(),
summary.dominant_child_count_count,
summary
.dominant_saved_primary_child_byte_hex
.as_deref()
.unwrap_or("0x00"),
summary.dominant_saved_primary_child_byte_count,
summary
.dominant_first_name_tag_relative_offset
.unwrap_or_default(),
summary.dominant_first_name_tag_relative_offset_count,
summary.rows_with_first_name_tag_at_offset_3
)
})
.unwrap_or_else(|| {
"no live-entry prelude summary was available".to_string()
}),
dominant_compact_prefix_pattern
.map(|pattern| {
format!(
"dominant compact prefix pattern {} / {} / {} occurs {} times; section-like rows={}, cap-like rows={}, first names={:?}/{:?}",
pattern.prefix_leading_dword_hex,
pattern.prefix_trailing_word_hex,
pattern.prefix_separator_byte_hex,
pattern.count,
pattern.section_like_primary_name_count,
pattern.cap_like_primary_name_count,
pattern.first_primary_name,
pattern.first_secondary_name
)
})
.unwrap_or_else(|| {
"no dominant compact prefix pattern summary was available".to_string()
}),
],
});
}
None
}
fn summarize_placed_structure_dynamic_side_buffer_alignment(
side_buffer: &SmpSavePlacedStructureDynamicSideBufferProbe,
triplets: &SmpSavePlacedStructureRecordTripletProbe,
) -> SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
let triplet_name_pairs = triplets
.entries
.iter()
.map(|entry| (entry.primary_name.clone(), entry.secondary_name.clone()))
.collect::<BTreeSet<_>>();
let matched_name_pair_samples = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.take(5)
.cloned()
.collect::<Vec<_>>();
let unmatched_side_buffer_name_pair_samples = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
!triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.take(5)
.cloned()
.collect::<Vec<_>>();
let side_buffer_rows_with_matching_triplet_name_pair_count = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.map(|summary| summary.count)
.sum::<usize>();
let unique_side_buffer_name_pair_count = side_buffer.name_pair_summaries.len();
let overlapping_name_pair_count = side_buffer
.name_pair_summaries
.iter()
.filter(|summary| {
triplet_name_pairs
.contains(&(summary.primary_name.clone(), summary.secondary_name.clone()))
})
.count();
SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
unique_side_buffer_name_pair_count,
unique_triplet_name_pair_count: triplet_name_pairs.len(),
overlapping_name_pair_count,
side_buffer_row_count: side_buffer.decoded_embedded_name_row_count,
side_buffer_rows_with_matching_triplet_name_pair_count,
side_buffer_rows_without_matching_triplet_name_pair_count: side_buffer
.decoded_embedded_name_row_count
.saturating_sub(side_buffer_rows_with_matching_triplet_name_pair_count),
triplet_name_pairs_without_side_buffer_match_count: triplet_name_pairs
.len()
.saturating_sub(overlapping_name_pair_count),
matched_name_pair_samples,
unmatched_side_buffer_name_pair_samples,
evidence: vec![
"placed-structure dynamic side-buffer alignment compares decoded 0x38a5 embedded name pairs against the grounded 0x36b1 triplet name-pair corpus".to_string(),
format!(
"{} of {} decoded side-buffer rows currently reuse name pairs already present in the placed-structure triplet owner seam",
side_buffer_rows_with_matching_triplet_name_pair_count,
side_buffer.decoded_embedded_name_row_count
),
format!(
"{} of {} unique side-buffer name pairs overlap the grounded triplet name-pair corpus",
overlapping_name_pair_count,
unique_side_buffer_name_pair_count
),
],
}
}
#[derive(Clone, Copy)]
struct IndexedCollectionHeaderSummary {
metadata_tag_offset: usize,
records_tag_offset: usize,
close_tag_offset: usize,
direct_collection_flag: u32,
direct_record_stride: u32,
live_id_bound: u32,
live_record_count: u32,
header_words: [u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT],
}
fn parse_save_tagged_collection_header_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
metadata_tag: u32,
records_tag: u32,
close_tag: u32,
source_kind: &str,
semantic_family: &str,
predicate: impl Fn(IndexedCollectionHeaderSummary) -> bool,
mut evidence: Vec<String>,
) -> Option<SmpSaveTaggedCollectionHeaderProbe> {
if file_extension_hint != Some("gms") {
return None;
}
let profile = container_profile?;
if !matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
) {
return None;
}
let metadata_offsets = find_u32_le_offsets(bytes, metadata_tag);
let records_offsets = find_u32_le_offsets(bytes, records_tag);
let close_offsets = find_u32_le_offsets(bytes, close_tag);
let summary = metadata_offsets
.into_iter()
.filter_map(|metadata_tag_offset| {
let records_tag_offset = records_offsets
.iter()
.copied()
.find(|offset| *offset > metadata_tag_offset)?;
let close_tag_offset = close_offsets
.iter()
.copied()
.find(|offset| *offset > records_tag_offset)?;
let payload = bytes.get(metadata_tag_offset + 4..records_tag_offset)?;
if payload.len() < INDEXED_COLLECTION_SERIALIZED_HEADER_LEN {
return None;
}
let header_words = (0..INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT)
.map(|index| read_u32_at(payload, index * 4))
.collect::<Option<Vec<_>>>()?;
let header_words: [u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT] =
header_words.try_into().ok()?;
let summary = IndexedCollectionHeaderSummary {
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
direct_collection_flag: header_words[0],
direct_record_stride: header_words[1],
live_id_bound: header_words[4],
live_record_count: header_words[5],
header_words,
};
predicate(summary).then_some(summary)
})
.next()?;
evidence.push(format!(
"exact little-endian u32 tag family 0x{metadata_tag:04x}/0x{records_tag:04x}/0x{close_tag:04x} appears at file offsets 0x{:x}/0x{:x}/0x{:x}",
summary.metadata_tag_offset, summary.records_tag_offset, summary.close_tag_offset
));
evidence.push(format!(
"header words report direct_collection_flag={}, direct_record_stride=0x{:x}, live_id_bound={}, live_record_count={}",
summary.direct_collection_flag,
summary.direct_record_stride,
summary.live_id_bound,
summary.live_record_count
));
Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: profile.profile_family.clone(),
source_kind: source_kind.to_string(),
semantic_family: semantic_family.to_string(),
metadata_tag_offset: summary.metadata_tag_offset,
records_tag_offset: summary.records_tag_offset,
close_tag_offset: summary.close_tag_offset,
direct_collection_flag: summary.direct_collection_flag,
direct_collection_flag_hex: format!("0x{:08x}", summary.direct_collection_flag),
direct_record_stride: summary.direct_record_stride,
direct_record_stride_hex: format!("0x{:08x}", summary.direct_record_stride),
live_id_bound: summary.live_id_bound,
live_id_bound_hex: format!("0x{:08x}", summary.live_id_bound),
live_record_count: summary.live_record_count,
live_record_count_hex: format!("0x{:08x}", summary.live_record_count),
header_words: summary.header_words.to_vec(),
header_hex_words: summary
.header_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
evidence,
})
}
fn scan_save_unclassified_tagged_collection_header_probes(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe> {
if file_extension_hint != Some("gms") {
return Vec::new();
}
let Some(profile) = container_profile else {
return Vec::new();
};
if !matches!(
profile.profile_family.as_str(),
"rt3-classic-save-container-v1"
| "rt3-105-save-container-v1"
| "rt3-105-scenario-save-container-v1"
| "rt3-105-alt-save-container-v1"
) {
return Vec::new();
}
let known_metadata_tags = BTreeSet::from([
RT3_SAVE_WORLD_BLOCK_CHUNK_TAG,
0x000061a9,
0x00005209,
0x000036b1,
EVENT_RUNTIME_COLLECTION_METADATA_TAG as u32,
]);
let mut low_tag_offsets: BTreeMap<u32, Vec<usize>> = BTreeMap::new();
for offset in 0..bytes.len().saturating_sub(4) {
let Some(tag) = read_u32_at(bytes, offset) else {
continue;
};
if (3..=0xffff).contains(&tag) {
low_tag_offsets.entry(tag).or_default().push(offset);
}
}
let mut probes = Vec::new();
for (&metadata_tag, metadata_offsets) in &low_tag_offsets {
if known_metadata_tags.contains(&metadata_tag) {
continue;
}
let Some(records_offsets) = low_tag_offsets.get(&(metadata_tag + 1)) else {
continue;
};
let Some(close_offsets) = low_tag_offsets.get(&(metadata_tag + 2)) else {
continue;
};
let records_tag = metadata_tag + 1;
let close_tag = metadata_tag + 2;
for &metadata_tag_offset in metadata_offsets {
let mut header_words = [0u32; INDEXED_COLLECTION_SERIALIZED_HEADER_DWORD_COUNT];
let mut valid_header = true;
for (index, word) in header_words.iter_mut().enumerate() {
let Some(value) = read_u32_at(bytes, metadata_tag_offset + 4 + index * 4) else {
valid_header = false;
break;
};
*word = value;
}
if !valid_header {
continue;
}
let summary = IndexedCollectionHeaderSummary {
metadata_tag_offset,
records_tag_offset: 0,
close_tag_offset: 0,
direct_collection_flag: header_words[0],
direct_record_stride: header_words[1],
live_id_bound: header_words[4],
live_record_count: header_words[5],
header_words,
};
if !matches!(summary.direct_collection_flag, 0 | 1)
|| summary.direct_record_stride == 0
|| summary.direct_record_stride > 0x2000
|| summary.live_id_bound == 0
|| summary.live_record_count == 0
|| summary.live_record_count > summary.live_id_bound
|| summary.live_id_bound > 0x1000
|| summary.live_record_count > 0x1000
{
continue;
}
let records_search_start = metadata_tag_offset + 4;
let records_index =
records_offsets.partition_point(|offset| *offset < records_search_start);
let Some(&records_tag_offset) = records_offsets.get(records_index) else {
continue;
};
let close_search_start = records_tag_offset + 4;
let close_index = close_offsets.partition_point(|offset| *offset < close_search_start);
let Some(&close_tag_offset) = close_offsets.get(close_index) else {
continue;
};
let records_span_len = close_tag_offset.saturating_sub(records_tag_offset + 4);
if records_span_len == 0 || records_span_len < summary.live_record_count as usize {
continue;
}
if probes
.iter()
.any(|probe: &SmpSaveUnclassifiedTaggedCollectionHeaderProbe| {
probe.metadata_tag_offset == metadata_tag_offset
&& probe.records_tag_offset == records_tag_offset
&& probe.close_tag_offset == close_tag_offset
})
{
continue;
}
probes.push(SmpSaveUnclassifiedTaggedCollectionHeaderProbe {
profile_family: profile.profile_family.clone(),
source_kind: "save-unclassified-tagged-header-counts".to_string(),
semantic_family: "scenario-save-unclassified-tagged-header-counts".to_string(),
metadata_tag,
metadata_tag_hex: format!("0x{metadata_tag:08x}"),
records_tag,
records_tag_hex: format!("0x{records_tag:08x}"),
close_tag,
close_tag_hex: format!("0x{close_tag:08x}"),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
records_span_len,
direct_collection_flag: summary.direct_collection_flag,
direct_collection_flag_hex: format!("0x{:08x}", summary.direct_collection_flag),
direct_record_stride: summary.direct_record_stride,
direct_record_stride_hex: format!("0x{:08x}", summary.direct_record_stride),
live_id_bound: summary.live_id_bound,
live_id_bound_hex: format!("0x{:08x}", summary.live_id_bound),
live_record_count: summary.live_record_count,
live_record_count_hex: format!("0x{:08x}", summary.live_record_count),
header_words: summary.header_words.to_vec(),
header_hex_words: summary
.header_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect(),
evidence: vec![
"generic save-side tagged collection scan over plausible low u32 metadata tags not yet claimed by the checked-in collection probes".to_string(),
"candidate uses adjacent metadata/records/close tags with a header that matches the grounded indexed-collection shape (flag, stride, live_id_bound, live_record_count)".to_string(),
],
});
}
}
probes.sort_by(|left, right| {
right
.live_record_count
.cmp(&left.live_record_count)
.then_with(|| left.metadata_tag.cmp(&right.metadata_tag))
.then_with(|| left.metadata_tag_offset.cmp(&right.metadata_tag_offset))
});
probes.truncate(32);
probes
}
fn filter_unclassified_tagged_collection_header_probes_outside_known_spans(
probes: Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe>,
known_header_probes: &[Option<&SmpSaveTaggedCollectionHeaderProbe>],
) -> Vec<SmpSaveUnclassifiedTaggedCollectionHeaderProbe> {
probes
.into_iter()
.filter(|probe| {
!known_header_probes.iter().flatten().any(|known| {
probe.metadata_tag_offset >= known.metadata_tag_offset
&& probe.close_tag_offset <= known.close_tag_offset
})
})
.collect()
}
fn parse_save_len_prefixed_ascii_name(bytes: &[u8]) -> Option<String> {
let len = *bytes.first()? as usize;
let text_bytes = bytes.get(1..1 + len)?;
let text = std::str::from_utf8(text_bytes).ok()?.trim_end_matches('\0');
Some(text.to_string())
}
fn parse_save_varlen_ascii_name_at(bytes: &[u8], offset: usize) -> Option<(String, usize)> {
let first = *bytes.get(offset)?;
if first == 0 {
return None;
}
let (len, header_len) = if first <= 0x7f {
(first as usize, 1usize)
} else {
let second = *bytes.get(offset + 1)? as usize;
((((first as usize) & 0x7f) << 8) | second, 2usize)
};
let start = offset + header_len;
let end = start.checked_add(len)?;
let text = std::str::from_utf8(bytes.get(start..end)?)
.ok()?
.trim_end_matches('\0')
.to_string();
Some((text, end))
}
fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, String)> {
let (first, second, _) = parse_save_len_prefixed_ascii_name_triplet(bytes)?;
Some((first, second))
}
fn parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(
bytes: &[u8],
) -> Option<((String, String, Option<String>), usize)> {
let (first, first_end) = parse_save_varlen_ascii_name_at(bytes, 0)?;
let mut second_len_offset = first_end;
while matches!(bytes.get(second_len_offset), Some(0)) {
second_len_offset += 1;
}
let (second, second_end) = parse_save_varlen_ascii_name_at(bytes, second_len_offset)?;
if first.is_empty() || second.is_empty() {
return None;
}
let mut third_len_offset = second_end;
while matches!(bytes.get(third_len_offset), Some(0)) {
third_len_offset += 1;
}
let (third, consumed_len) = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
.map(|(text, end)| {
let third = (!text.is_empty()).then_some(text);
(third, end)
})
.unwrap_or((None, second_end));
Some(((first, second, third), consumed_len))
}
fn parse_save_len_prefixed_ascii_name_triplet(
bytes: &[u8],
) -> Option<(String, String, Option<String>)> {
let ((first, second, third), _) =
parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(bytes)?;
Some((first, second, third))
}
fn parse_save_fixed_ascii_name(bytes: &[u8]) -> Option<String> {
let nul_index = bytes
.iter()
.position(|byte| *byte == 0)
.unwrap_or(bytes.len());
let text = std::str::from_utf8(bytes.get(..nul_index)?).ok()?;
if text.is_empty()
|| !text
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b' ' | b'-' | b'&' | b'/'))
{
return None;
}
Some(text.to_string())
}
fn parse_save_region_profile_collection_probe(
profile_payload: &[u8],
) -> Option<SmpSaveRegionProfileCollectionProbe> {
let direct_collection_flag = read_u32_at(profile_payload, 0)?;
let entry_stride = read_u32_at(profile_payload, 4)?;
let header_word_2 = read_u32_at(profile_payload, 8)?;
let header_word_3 = read_u32_at(profile_payload, 12)?;
let live_id_bound = read_u32_at(profile_payload, 16)?;
let live_record_count = read_u32_at(profile_payload, 20)?;
let header_word_6 = read_u32_at(profile_payload, 24)?;
let header_word_7 = read_u32_at(profile_payload, 28)?;
if !(direct_collection_flag == 1
&& entry_stride == 0x22
&& header_word_2 == 2
&& header_word_3 == 2
&& live_record_count > 0
&& live_record_count < live_id_bound
&& header_word_6 == 0
&& header_word_7 == 1)
{
return None;
}
let entry_stride = entry_stride as usize;
let live_record_count_usize = live_record_count as usize;
let rows_byte_len = live_record_count_usize.checked_mul(entry_stride)?;
let mut matched_probe = None;
for entry_start_relative_offset in 0x20..=0x80 {
if entry_start_relative_offset + rows_byte_len > profile_payload.len() {
break;
}
let mut entries = Vec::with_capacity(live_record_count_usize);
let mut matched = true;
for entry_index in 0..live_record_count_usize {
let row_relative_offset = entry_start_relative_offset + entry_index * entry_stride;
let row =
profile_payload.get(row_relative_offset..row_relative_offset + entry_stride)?;
let name = match parse_save_fixed_ascii_name(row.get(..12)?) {
Some(name) => name,
None => {
matched = false;
break;
}
};
let trailing_weight_f32 = f32::from_bits(read_u32_at(row, entry_stride - 4)?);
if !trailing_weight_f32.is_finite() || trailing_weight_f32 < 0.0 {
matched = false;
break;
}
entries.push(SmpSaveRegionProfileEntryProbe {
entry_index,
row_relative_offset,
name,
trailing_weight_f32,
});
}
if matched {
matched_probe = Some(SmpSaveRegionProfileCollectionProbe {
direct_collection_flag,
entry_stride: entry_stride as u32,
live_id_bound,
live_record_count,
entry_start_relative_offset,
trailing_padding_len: profile_payload.len()
- (entry_start_relative_offset + rows_byte_len),
entries,
});
break;
}
}
matched_probe
}
fn parse_rt3_105_save_name_table_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
bridge_payload_probe: Option<&SmpRt3105SaveBridgePayloadProbe>,
) -> Option<SmpRt3105SaveNameTableProbe> {
let (
profile_family,
source_kind,
header_offset,
entries_offset,
block_end_offset,
mut evidence,
) = if let Some(payload) = bridge_payload_probe {
(
payload.profile_family.clone(),
"save-bridge-secondary-block".to_string(),
payload.secondary_block_offset + 0x354,
payload.secondary_block_offset + 0x3b5,
payload.secondary_block_end_offset,
vec![
"common-save bridge payload branch".to_string(),
format!(
"secondary block span 0x{:x}..0x{:x}",
payload.secondary_block_offset, payload.secondary_block_end_offset
),
],
)
} else {
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let extension = file_extension_hint.unwrap_or("");
let source_kind = match extension {
"gmp" => "map-fixed-catalog-range",
"gms" => "save-fixed-catalog-range",
"gmx" => "sandbox-fixed-catalog-range",
_ => "fixed-catalog-range",
}
.to_string();
(
profile_family,
source_kind,
0x6a70,
0x6ad1,
0x73c0,
vec![
"fixed catalog range branch".to_string(),
"using observed shared 1.05 candidate-availability table offsets".to_string(),
],
)
};
let entry_stride = 0x22usize;
if block_end_offset > bytes.len() {
return None;
}
if !matches_candidate_availability_table_header(bytes, header_offset) {
return None;
}
let observed_entry_capacity = read_u32_at(bytes, header_offset + 0x1c)? as usize;
let observed_entry_count = read_u32_at(bytes, header_offset + 0x20)? as usize;
let entries_len = observed_entry_count.checked_mul(entry_stride)?;
let entries_end_offset = entries_offset.checked_add(entries_len)?;
if observed_entry_count == 0 || observed_entry_capacity < observed_entry_count {
return None;
}
if entries_end_offset > block_end_offset || entries_end_offset > bytes.len() {
return None;
}
let mut entries = Vec::with_capacity(observed_entry_count);
for index in 0..observed_entry_count {
let offset = entries_offset + index * entry_stride;
let chunk = &bytes[offset..offset + entry_stride];
let nul_index = chunk
.iter()
.position(|byte| *byte == 0)
.unwrap_or(entry_stride);
let text = std::str::from_utf8(&chunk[..nul_index]).ok()?.to_string();
let trailer_word = read_u32_at(bytes, offset + entry_stride - 4)?;
entries.push(SmpRt3105SaveNameTableEntry {
index,
offset,
text,
availability_dword: trailer_word,
availability_dword_hex: format!("0x{trailer_word:08x}"),
trailer_word,
trailer_word_hex: format!("0x{trailer_word:08x}"),
});
}
let zero_trailer_entry_names = entries
.iter()
.filter(|entry| entry.trailer_word == 0)
.map(|entry| entry.text.clone())
.collect::<Vec<_>>();
let zero_trailer_entry_count = zero_trailer_entry_names.len();
let nonzero_trailer_entry_count = entries.len().saturating_sub(zero_trailer_entry_count);
let mut distinct_trailer_words = entries
.iter()
.map(|entry| entry.trailer_word)
.collect::<Vec<_>>();
distinct_trailer_words.sort_unstable();
distinct_trailer_words.dedup();
let distinct_trailer_hex_words = distinct_trailer_words
.iter()
.map(|word| format!("0x{word:08x}"))
.collect::<Vec<_>>();
let trailing_footer_hex = hex_encode(&bytes[entries_end_offset..block_end_offset]);
let footer = &bytes[entries_end_offset..block_end_offset];
if footer.len() != 9 {
return None;
}
let footer_progress_word_0 = u32::from_le_bytes([footer[0], footer[1], footer[2], footer[3]]);
let footer_progress_word_1 = u32::from_le_bytes([footer[4], footer[5], footer[6], footer[7]]);
let footer_trailing_byte = footer[8];
let mut footer_grounded_alignments = Vec::new();
for value in [footer_progress_word_0, footer_progress_word_1] {
if let Some(alignment) = classify_name_table_footer_progress_alignment(value) {
footer_grounded_alignments.push(alignment.to_string());
}
}
evidence.extend([
format!("header offset 0x{header_offset:08x}"),
format!("entries offset 0x{entries_offset:08x}"),
format!("entry stride 0x{entry_stride:x}"),
format!("observed entry capacity {}", observed_entry_capacity),
format!("observed entry count {}", observed_entry_count),
format!("zero-trailer entries {}", zero_trailer_entry_count),
format!(
"trailing footer {} bytes after last entry",
block_end_offset - entries_end_offset
),
]);
let semantic_alignment = vec![
"Matches the grounded scenario-side named candidate-availability table shape under 0x00437743.".to_string(),
"Entry layout matches 0x00434ea0/0x00434f20: name slot at +0x00..+0x1d and availability dword at +0x1e.".to_string(),
"The shared map/save range suggests this catalog is bundled in source map content and later mirrored into scenario state [state+0x66b2].".to_string(),
];
Some(SmpRt3105SaveNameTableProbe {
profile_family,
source_kind,
semantic_family: "scenario-named-candidate-availability-table".to_string(),
semantic_alignment,
header_offset,
header_word_0: read_u32_at(bytes, header_offset)?,
header_word_0_hex: format!("0x{:08x}", read_u32_at(bytes, header_offset)?),
header_word_1: read_u32_at(bytes, header_offset + 4)?,
header_word_1_hex: format!("0x{:08x}", read_u32_at(bytes, header_offset + 4)?),
header_word_2: read_u32_at(bytes, header_offset + 8)?,
header_word_2_hex: format!("0x{:08x}", read_u32_at(bytes, header_offset + 8)?),
entry_stride,
entry_stride_hex: format!("0x{entry_stride:x}"),
header_prefix_word_count: 11,
observed_entry_capacity,
observed_entry_count,
zero_trailer_entry_count,
nonzero_trailer_entry_count,
distinct_trailer_words,
distinct_trailer_hex_words,
zero_trailer_entry_names,
entries_offset,
entries_end_offset,
trailing_footer_hex,
footer_progress_word_0,
footer_progress_word_0_hex: format!("0x{footer_progress_word_0:08x}"),
footer_progress_word_1,
footer_progress_word_1_hex: format!("0x{footer_progress_word_1:08x}"),
footer_trailing_byte,
footer_trailing_byte_hex: format!("0x{footer_trailing_byte:02x}"),
footer_grounded_alignments,
entries,
evidence,
})
}
const RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE: usize = 0x41;
const RT3_105_SAVE_NAMED_LOCOMOTIVE_MIN_ENTRY_COUNT: usize = 8;
const RT3_105_SAVE_NAMED_LOCOMOTIVE_MAX_SEARCH_SPAN: usize = 0x4000;
fn parse_rt3_105_save_named_locomotive_availability_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
packed_profile_probe: Option<&SmpRt3105PackedProfileProbe>,
) -> Option<SmpRt3105SaveNamedLocomotiveAvailabilityProbe> {
let packed_profile_probe = packed_profile_probe?;
let extension = file_extension_hint.unwrap_or("");
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| packed_profile_probe.profile_family.clone());
if !matches!(extension, "gms" | "gmx") || !profile_family.contains("save-container") {
return None;
}
let search_start = packed_profile_probe
.packed_profile_offset
.checked_add(packed_profile_probe.packed_profile_len)?;
let search_end = search_start
.checked_add(RT3_105_SAVE_NAMED_LOCOMOTIVE_MAX_SEARCH_SPAN)
.map(|end| end.min(bytes.len()))
.unwrap_or(bytes.len());
if search_end <= search_start + RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE {
return None;
}
let mut best_start = None;
let mut best_entries = Vec::new();
for candidate_start in search_start..search_end {
let entries = parse_direct_named_locomotive_entries(bytes, candidate_start, search_end);
if entries.len() > best_entries.len() {
best_entries = entries;
best_start = Some(candidate_start);
}
}
if best_entries.len() < RT3_105_SAVE_NAMED_LOCOMOTIVE_MIN_ENTRY_COUNT {
return None;
}
let entries_offset = best_start?;
let entries_end_offset = entries_offset
.checked_add(best_entries.len() * RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE)?;
let zero_availability_names = best_entries
.iter()
.filter(|entry| entry.availability_dword == 0)
.map(|entry| entry.text.clone())
.collect::<Vec<_>>();
let zero_availability_count = zero_availability_names.len();
let source_kind = match extension {
"gms" => "save-direct-locomotive-row-run",
"gmx" => "sandbox-direct-locomotive-row-run",
_ => "direct-locomotive-row-run",
}
.to_string();
let observed_entry_count = best_entries.len();
Some(SmpRt3105SaveNamedLocomotiveAvailabilityProbe {
profile_family,
source_kind,
semantic_family: "scenario-named-locomotive-availability-table".to_string(),
semantic_alignment: vec![
"Matches the grounded `.smp` save-side locomotive-name-plus-dword row family restored into scenario state [world+0x66b6].".to_string(),
"Entry layout is one availability dword at +0x00 followed by one fixed-width locomotive name buffer at +0x04..+0x40.".to_string(),
"The recovered row order is treated conservatively as the live locomotive ordinal order later used by locomotives-page descriptor lowering.".to_string(),
],
entries_offset,
entry_stride: RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE,
entry_stride_hex: format!("0x{:x}", RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE),
observed_entry_count,
zero_availability_count,
zero_availability_names,
entries_end_offset,
entries: best_entries,
evidence: vec![
format!("search span 0x{search_start:08x}..0x{search_end:08x}"),
format!("entries offset 0x{entries_offset:08x}"),
format!(
"entry stride 0x{:x}",
RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE
),
format!("observed entry count {observed_entry_count}"),
],
})
}
fn parse_direct_named_locomotive_entries(
bytes: &[u8],
start_offset: usize,
search_end: usize,
) -> Vec<SmpRt3105SaveNameTableEntry> {
let mut entries = Vec::new();
let mut offset = start_offset;
while offset + RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE <= bytes.len() && offset < search_end
{
let record = &bytes[offset..offset + RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE];
let Some(nul_index) = record[4..].iter().position(|byte| *byte == 0) else {
break;
};
let name_bytes = &record[4..4 + nul_index];
if name_bytes.is_empty() {
break;
}
let Ok(text) = std::str::from_utf8(name_bytes) else {
break;
};
if !is_probable_named_locomotive_label(text) {
break;
}
if record[4 + nul_index + 1..].iter().any(|byte| *byte != 0) {
break;
}
let availability_dword = u32::from_le_bytes([record[0], record[1], record[2], record[3]]);
entries.push(SmpRt3105SaveNameTableEntry {
index: entries.len(),
offset,
text: text.to_string(),
availability_dword,
availability_dword_hex: format!("0x{availability_dword:08x}"),
trailer_word: availability_dword,
trailer_word_hex: format!("0x{availability_dword:08x}"),
});
offset += RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE;
}
entries
}
fn is_probable_named_locomotive_label(text: &str) -> bool {
if text.is_empty() || text.len() > 40 {
return false;
}
text.bytes().all(|byte| {
byte.is_ascii_alphanumeric() || matches!(byte, b' ' | b'-' | b'/' | b'(' | b')' | b'.')
})
}
fn parse_special_conditions_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
) -> Option<SmpSpecialConditionsProbe> {
let table_len = SPECIAL_CONDITION_COUNT.checked_mul(4)?;
let table_end = SPECIAL_CONDITIONS_OFFSET.checked_add(table_len)?;
if table_end > bytes.len() {
return None;
}
let mut entries = Vec::with_capacity(SPECIAL_CONDITION_COUNT);
for definition in KNOWN_SPECIAL_CONDITION_DEFINITIONS {
let value = read_u32_at(
bytes,
SPECIAL_CONDITIONS_OFFSET + (definition.slot_index as usize) * 4,
)?;
if value > 1 {
return None;
}
entries.push(SmpSpecialConditionEntry {
slot_index: definition.slot_index,
hidden: definition.hidden,
label_id: definition.label_id,
help_id: definition.help_id,
label: definition.label.to_string(),
value,
value_hex: format!("0x{value:08x}"),
});
}
let hidden_sentinel = entries
.iter()
.find(|entry| entry.slot_index == SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT as u8)?;
if hidden_sentinel.value != 1 {
return None;
}
let enabled_visible_labels = entries
.iter()
.filter(|entry| !entry.hidden && entry.value != 0)
.map(|entry| entry.label.clone())
.collect::<Vec<_>>();
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "map-fixed-special-conditions-range",
"gms" => "save-fixed-special-conditions-range",
"gmx" => "sandbox-fixed-special-conditions-range",
_ => "fixed-special-conditions-range",
}
.to_string();
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let mut evidence = vec![
format!("fixed 36-dword range at 0x{SPECIAL_CONDITIONS_OFFSET:04x}"),
"all observed lanes are boolean dwords".to_string(),
"hidden slot 35 carries the expected sentinel value 1".to_string(),
"slot metadata matches the grounded editor special-conditions table at 0x005f3ab0"
.to_string(),
];
if enabled_visible_labels.is_empty() {
evidence.push("no visible special conditions enabled in this file".to_string());
} else {
evidence.push(format!(
"enabled visible conditions: {}",
enabled_visible_labels.join(", ")
));
}
Some(SmpSpecialConditionsProbe {
profile_family,
source_kind,
table_offset: SPECIAL_CONDITIONS_OFFSET,
table_len,
enabled_visible_count: enabled_visible_labels.len(),
enabled_visible_labels,
hidden_sentinel_slot_index: SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT as u8,
hidden_sentinel_value: hidden_sentinel.value,
hidden_sentinel_value_hex: hidden_sentinel.value_hex.clone(),
entries,
evidence,
})
}
fn parse_post_special_conditions_scalar_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpPostSpecialConditionsScalarProbe> {
special_conditions_probe?;
if POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET > bytes.len() {
return None;
}
let dword_count =
(POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET - POST_SPECIAL_CONDITIONS_SCALAR_OFFSET) / 4;
let mut nonzero_lanes = Vec::new();
for index in 0..dword_count {
let absolute_offset = POST_SPECIAL_CONDITIONS_SCALAR_OFFSET + index * 4;
let value = read_u32_at(bytes, absolute_offset)?;
if value == 0 {
continue;
}
nonzero_lanes.push(SmpPostSpecialConditionsScalarLane {
absolute_offset,
relative_offset: absolute_offset - POST_SPECIAL_CONDITIONS_SCALAR_OFFSET,
absolute_offset_hex: format!("0x{absolute_offset:04x}"),
relative_offset_hex: format!(
"0x{:x}",
absolute_offset - POST_SPECIAL_CONDITIONS_SCALAR_OFFSET
),
value,
value_hex: format!("0x{value:08x}"),
probable_f32_le: probable_normal_f32_string(value),
});
}
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "map-post-special-conditions-window",
"gms" => "save-post-special-conditions-window",
"gmx" => "sandbox-post-special-conditions-window",
_ => "post-special-conditions-window",
}
.to_string();
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let first_nonzero_offset = nonzero_lanes.first().map(|lane| lane.absolute_offset);
let last_nonzero_offset = nonzero_lanes.last().map(|lane| lane.absolute_offset);
let overlap_nonzero_relative_offset_hexes = nonzero_lanes
.iter()
.filter(|lane| lane.absolute_offset < POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET)
.map(|lane| lane.relative_offset_hex.clone())
.collect::<Vec<_>>();
let tail_nonzero_lanes = nonzero_lanes
.iter()
.filter(|lane| lane.absolute_offset >= POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET)
.cloned()
.collect::<Vec<_>>();
let tail_first_nonzero_offset = tail_nonzero_lanes.first().map(|lane| lane.absolute_offset);
let tail_last_nonzero_offset = tail_nonzero_lanes.last().map(|lane| lane.absolute_offset);
let tail_nonzero_relative_offset_hexes = tail_nonzero_lanes
.iter()
.map(|lane| lane.relative_offset_hex.clone())
.collect::<Vec<_>>();
let grounded_text_field_remaining_file_window = &bytes[POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
..POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET];
let mut grounded_text_field_remaining_nonzero_offsets = Vec::new();
for (index, byte) in grounded_text_field_remaining_file_window.iter().enumerate() {
if *byte != 0 {
grounded_text_field_remaining_nonzero_offsets
.push(POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET + index);
}
}
let grounded_text_field_remaining_first_nonzero_offset =
grounded_text_field_remaining_nonzero_offsets
.first()
.copied();
let grounded_text_field_remaining_last_nonzero_offset =
grounded_text_field_remaining_nonzero_offsets
.last()
.copied();
let mut evidence = vec![
format!(
"fixed post-sentinel dword window at 0x{POST_SPECIAL_CONDITIONS_SCALAR_OFFSET:04x}..0x{POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET:04x}"
),
"window starts immediately after the hidden special-conditions sentinel slot at 0x0df0"
.to_string(),
format!(
"leading overlap prefix 0x{POST_SPECIAL_CONDITIONS_SCALAR_OFFSET:04x}..0x{POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET:04x} aliases aligned runtime-rule band indices {}..{}",
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX,
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
+ SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
- 1
),
format!("save-only tail begins at 0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET:04x}"),
format!(
"that tail is offset-aligned with live runtime object bytes [world+0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_OFFSET:04x}..+0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET:04x}]"
),
format!(
"the tail start lands on the grounded live field [world+0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET:04x}], a 0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN:x}-byte status-text buffer written by win/lose and winner-announcement helpers"
),
format!(
"current dword scan stops at 0x{POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET:04x}, leaving one byte-aligned continuation window 0x{POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET:04x}..0x{POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET:04x} before the next clean live-field edge at [world+0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET:04x}]"
),
format!(
"the next exact grounded fields after that edge begin at [world+0x{POST_TEXT_FIELD_0_RUNTIME_OBJECT_OFFSET:04x}], [world+0x{POST_TEXT_FIELD_1_RUNTIME_OBJECT_OFFSET:04x}], [world+0x{POST_TEXT_FIELD_2_RUNTIME_OBJECT_OFFSET:04x}], [world+0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET:04x}], and [world+0x{POST_TEXT_FIELD_4_RUNTIME_OBJECT_OFFSET:04x}], which map to file offsets 0x{POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET:04x}, 0x0f5d, 0x0f61, 0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_FILE_OFFSET:04x}, and 0x0f6d"
),
format!(
"the first grounded dword-sized fields after that edge are [world+0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET:04x}] and [world+0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_OFFSET:04x}], which would land at file offsets 0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_FILE_OFFSET:04x} and 0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_FILE_OFFSET:04x}"
),
];
if nonzero_lanes.is_empty() {
evidence.push(
"all observed dwords in this post-sentinel window are zero for this file".to_string(),
);
} else {
evidence.push(format!(
"observed {} nonzero dword lanes between {} and {}",
nonzero_lanes.len(),
nonzero_lanes
.first()
.map(|lane| lane.absolute_offset_hex.as_str())
.unwrap_or("n/a"),
nonzero_lanes
.last()
.map(|lane| lane.absolute_offset_hex.as_str())
.unwrap_or("n/a")
));
if nonzero_lanes
.iter()
.all(|lane| lane.probable_f32_le.is_some())
{
evidence.push(
"every nonzero lane in this window also decodes as a normal finite little-endian f32"
.to_string(),
);
}
evidence.push(format!(
"{} nonzero lanes fall inside the aligned-band overlap prefix and {} fall inside the later tail",
overlap_nonzero_relative_offset_hexes.len(),
tail_nonzero_lanes.len()
));
}
evidence.push(
"checked file bytes in the later tail are not yet validated as a byte-for-byte mirror of the live object, because the region aligned to [world+0x4b47] does not currently decode as preserved text in the checked saves"
.to_string(),
);
if grounded_text_field_remaining_nonzero_offsets.is_empty() {
evidence.push(
"the remaining file window through the grounded text-field edge is all zero in this file"
.to_string(),
);
} else {
evidence.push(format!(
"the remaining file window through the grounded text-field edge still has {} nonzero bytes between 0x{:04x} and 0x{:04x}",
grounded_text_field_remaining_nonzero_offsets.len(),
grounded_text_field_remaining_first_nonzero_offset.unwrap_or(0),
grounded_text_field_remaining_last_nonzero_offset.unwrap_or(0)
));
}
Some(SmpPostSpecialConditionsScalarProbe {
profile_family,
source_kind,
window_offset: POST_SPECIAL_CONDITIONS_SCALAR_OFFSET,
window_end_offset: POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET,
window_len: POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_OFFSET,
window_len_hex: format!(
"0x{:x}",
POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET - POST_SPECIAL_CONDITIONS_SCALAR_OFFSET
),
dword_count,
overlap_end_offset: POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET,
overlap_end_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET:04x}"
),
overlap_dword_count: (POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_OFFSET)
/ 4,
overlap_nonzero_dword_count: overlap_nonzero_relative_offset_hexes.len(),
overlap_nonzero_relative_offset_hexes,
tail_offset: POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET,
tail_offset_hex: format!("0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET:04x}"),
tail_len: POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET,
tail_len_hex: format!(
"0x{:x}",
POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET - POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET
),
tail_dword_count: (POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET)
/ 4,
tail_runtime_object_offset: POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_OFFSET,
tail_runtime_object_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_OFFSET:04x}"
),
tail_runtime_object_end_offset:
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET,
tail_runtime_object_end_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET:04x}"
),
tail_runtime_object_validated_byte_mirror: false,
tail_grounded_live_field_offset:
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET,
tail_grounded_live_field_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET:04x}"
),
tail_grounded_live_field_name: "victory-or-outcome status text buffer".to_string(),
tail_grounded_live_field_copy_len:
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN,
tail_grounded_live_field_copy_len_hex: format!(
"0x{:x}",
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN
),
tail_grounded_live_field_copy_end_offset:
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET,
tail_grounded_live_field_copy_end_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET:04x}"
),
tail_window_cuts_through_grounded_live_field:
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET
< POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET,
tail_grounded_live_field_remaining_file_window_offset:
POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET,
tail_grounded_live_field_remaining_file_window_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET:04x}"
),
tail_grounded_live_field_remaining_file_window_len:
POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET,
tail_grounded_live_field_remaining_file_window_len_hex: format!(
"0x{:x}",
POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET
- POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
),
tail_grounded_live_field_remaining_file_window_nonzero_byte_count:
grounded_text_field_remaining_nonzero_offsets.len(),
tail_grounded_live_field_remaining_file_window_first_nonzero_offset:
grounded_text_field_remaining_first_nonzero_offset,
tail_grounded_live_field_remaining_file_window_first_nonzero_offset_hex:
grounded_text_field_remaining_first_nonzero_offset
.map(|offset| format!("0x{offset:04x}")),
tail_grounded_live_field_remaining_file_window_last_nonzero_offset:
grounded_text_field_remaining_last_nonzero_offset,
tail_grounded_live_field_remaining_file_window_last_nonzero_offset_hex:
grounded_text_field_remaining_last_nonzero_offset
.map(|offset| format!("0x{offset:04x}")),
tail_next_grounded_dword_field_offset:
POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET,
tail_next_grounded_dword_field_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_OFFSET:04x}"
),
tail_next_grounded_dword_field_file_offset:
POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_FILE_OFFSET,
tail_next_grounded_dword_field_file_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_0_FILE_OFFSET:04x}"
),
tail_second_grounded_dword_field_offset:
POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_OFFSET,
tail_second_grounded_dword_field_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_OFFSET:04x}"
),
tail_second_grounded_dword_field_file_offset:
POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_FILE_OFFSET,
tail_second_grounded_dword_field_file_offset_hex: format!(
"0x{POST_SPECIAL_CONDITIONS_NEXT_GROUNDED_DWORD_FIELD_1_FILE_OFFSET:04x}"
),
post_text_field_file_alignment_matches_grounded_dword_fields: false,
tail_nonzero_dword_count: tail_nonzero_lanes.len(),
tail_first_nonzero_offset,
tail_first_nonzero_offset_hex: tail_first_nonzero_offset
.map(|offset| format!("0x{offset:04x}")),
tail_last_nonzero_offset,
tail_last_nonzero_offset_hex: tail_last_nonzero_offset
.map(|offset| format!("0x{offset:04x}")),
tail_nonzero_relative_offset_hexes,
nonzero_dword_count: nonzero_lanes.len(),
first_nonzero_offset,
first_nonzero_offset_hex: first_nonzero_offset.map(|offset| format!("0x{offset:04x}")),
last_nonzero_offset,
last_nonzero_offset_hex: last_nonzero_offset.map(|offset| format!("0x{offset:04x}")),
nonzero_lanes,
evidence,
})
}
fn parse_post_text_field_neighborhood_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpPostTextFieldNeighborhoodProbe> {
special_conditions_probe?;
if POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET > bytes.len() {
return None;
}
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "post-text-grounded-field-neighborhood",
"gms" => "post-text-grounded-field-neighborhood",
"gmx" => "post-text-grounded-field-neighborhood",
_ => "post-text-grounded-field-neighborhood",
}
.to_string();
let exact_fields = [
(
"Auto-Show Grade During Track Lay",
POST_TEXT_FIELD_0_RUNTIME_OBJECT_OFFSET,
POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET,
1usize,
),
(
"Starting Building Density Level",
POST_TEXT_FIELD_1_RUNTIME_OBJECT_OFFSET,
0x0f5dusize,
1usize,
),
(
"Building Density Growth",
POST_TEXT_FIELD_2_RUNTIME_OBJECT_OFFSET,
0x0f61usize,
1usize,
),
(
"leftover simulation time accumulator",
POST_TEXT_FIELD_3_RUNTIME_OBJECT_OFFSET,
0x0f65usize,
4usize,
),
(
"selected-year lane snapshot",
POST_TEXT_FIELD_4_RUNTIME_OBJECT_OFFSET,
0x0f6dusize,
1usize,
),
(
"late locomotive policy gate dword",
POST_TEXT_FIELD_5_RUNTIME_OBJECT_OFFSET,
0x0f71usize,
4usize,
),
];
let grounded_field_observations = exact_fields
.iter()
.map(
|(field_name, runtime_object_offset, file_offset, field_width_bytes)| {
let raw = &bytes[*file_offset..*file_offset + *field_width_bytes];
let raw_hex = hex_encode(raw);
let (value_u8, value_u8_hex, value_u32, value_u32_hex, probable_f32_le) =
if *field_width_bytes == 1 {
let value = raw[0];
(
Some(value),
Some(format!("0x{value:02x}")),
None,
None,
None,
)
} else {
let value = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]);
(
None,
None,
Some(value),
Some(format!("0x{value:08x}")),
probable_normal_f32_string(value),
)
};
SmpPostTextGroundedFieldObservation {
field_name: (*field_name).to_string(),
runtime_object_offset: *runtime_object_offset,
runtime_object_offset_hex: format!("0x{runtime_object_offset:04x}"),
file_offset: *file_offset,
file_offset_hex: format!("0x{file_offset:04x}"),
field_width_bytes: *field_width_bytes,
field_width_bytes_hex: format!("0x{field_width_bytes:x}"),
raw_hex,
value_u8,
value_u8_hex,
value_u32,
value_u32_hex,
probable_f32_le,
}
},
)
.collect::<Vec<_>>();
let one_byte_early_float_candidates = exact_fields
.iter()
.filter(|(_, _, file_offset, _)| *file_offset > 0)
.filter_map(|(field_name, runtime_object_offset, file_offset, _)| {
let candidate_offset = file_offset - 1;
let value = read_u32_at(bytes, candidate_offset)?;
let probable_f32_le = probable_normal_f32_string(value)?;
Some(SmpPostTextFloatAlignmentCandidate {
grounded_field_name: (*field_name).to_string(),
grounded_field_runtime_object_offset: *runtime_object_offset,
grounded_field_runtime_object_offset_hex: format!("0x{runtime_object_offset:04x}"),
grounded_field_file_offset: *file_offset,
grounded_field_file_offset_hex: format!("0x{file_offset:04x}"),
candidate_offset,
candidate_offset_hex: format!("0x{candidate_offset:04x}"),
candidate_value: value,
candidate_value_hex: format!("0x{value:08x}"),
probable_f32_le,
})
})
.collect::<Vec<_>>();
let mut evidence = vec![
format!(
"post-text grounded-field neighborhood spans file offsets 0x{POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET:04x}..0x{POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET:04x}"
),
"this neighborhood starts at the first grounded post-text field [world+0x4c74] and extends through the later dword at [world+0x4c8c]".to_string(),
"the exact grounded field offsets here are byte-oriented at 0x0f59, 0x0f5d, 0x0f61, and 0x0f6d, with dword-sized fields only at 0x0f65 and 0x0f71".to_string(),
];
if one_byte_early_float_candidates.is_empty() {
evidence.push(
"no one-byte-early little-endian float-looking starts were observed ahead of the grounded fields in this file".to_string(),
);
} else {
evidence.push(format!(
"observed {} float-looking 4-byte starts exactly one byte before grounded field offsets in this file",
one_byte_early_float_candidates.len()
));
}
Some(SmpPostTextFieldNeighborhoodProbe {
profile_family,
source_kind,
window_offset: POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET,
window_end_offset: POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET,
window_len: POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET - POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET,
window_len_hex: format!(
"0x{:x}",
POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET - POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET
),
grounded_field_observations,
one_byte_early_float_candidates,
evidence,
})
}
fn parse_locomotive_policy_neighborhood_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpLocomotivePolicyNeighborhoodProbe> {
special_conditions_probe?;
if LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET > bytes.len() {
return None;
}
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "locomotive-policy-neighborhood",
"gms" => "locomotive-policy-neighborhood",
"gmx" => "locomotive-policy-neighborhood",
_ => "locomotive-policy-neighborhood",
}
.to_string();
let exact_fields = [
(
"selected-year bucket companion scalar",
LOCOMOTIVE_POLICY_FIELD_NEG3_RUNTIME_OBJECT_OFFSET,
0x0f87usize,
4usize,
),
(
"startup-dispatch reset-owned band at +0x4cae",
LOCOMOTIVE_POLICY_FIELD_NEG2_RUNTIME_OBJECT_OFFSET,
0x0f93usize,
4usize,
),
(
"startup-dispatch reset-owned band at +0x4cb2",
LOCOMOTIVE_POLICY_FIELD_NEG1_RUNTIME_OBJECT_OFFSET,
0x0f97usize,
4usize,
),
(
"linked-site removal follow-on gate",
LOCOMOTIVE_POLICY_FIELD_0_RUNTIME_OBJECT_OFFSET,
0x0f78usize,
1usize,
),
(
"All Steam Locos Avail.",
LOCOMOTIVE_POLICY_FIELD_1_RUNTIME_OBJECT_OFFSET,
0x0f7cusize,
1usize,
),
(
"All Diesel Locos Avail.",
LOCOMOTIVE_POLICY_FIELD_2_RUNTIME_OBJECT_OFFSET,
0x0f7dusize,
1usize,
),
(
"All Electric Locos Avail.",
LOCOMOTIVE_POLICY_FIELD_3_RUNTIME_OBJECT_OFFSET,
0x0f7eusize,
1usize,
),
(
"station-list selected station id",
LOCOMOTIVE_POLICY_FIELD_4_RUNTIME_OBJECT_OFFSET,
0x0f9fusize,
4usize,
),
(
"cached available-locomotive rating",
LOCOMOTIVE_POLICY_FIELD_5_RUNTIME_OBJECT_OFFSET,
0x0fa3usize,
4usize,
),
];
let grounded_field_observations = exact_fields
.iter()
.map(
|(field_name, runtime_object_offset, file_offset, field_width_bytes)| {
let raw = &bytes[*file_offset..*file_offset + *field_width_bytes];
let raw_hex = hex_encode(raw);
let (value_u8, value_u8_hex, value_u32, value_u32_hex, probable_f32_le) =
if *field_width_bytes == 1 {
let value = raw[0];
(
Some(value),
Some(format!("0x{value:02x}")),
None,
None,
None,
)
} else {
let value = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]);
(
None,
None,
Some(value),
Some(format!("0x{value:08x}")),
probable_normal_f32_string(value),
)
};
SmpLocomotivePolicyFieldObservation {
field_name: (*field_name).to_string(),
runtime_object_offset: *runtime_object_offset,
runtime_object_offset_hex: format!("0x{runtime_object_offset:04x}"),
file_offset: *file_offset,
file_offset_hex: format!("0x{file_offset:04x}"),
field_width_bytes: *field_width_bytes,
field_width_bytes_hex: format!("0x{field_width_bytes:x}"),
raw_hex,
value_u8,
value_u8_hex,
value_u32,
value_u32_hex,
probable_f32_le,
}
},
)
.collect::<Vec<_>>();
let three_byte_early_float_candidates = exact_fields
.iter()
.filter(|(_, _, _, width)| *width == 4usize)
.filter_map(|(field_name, runtime_object_offset, file_offset, _)| {
let candidate_offset = file_offset.saturating_sub(3);
let value = read_u32_at(bytes, candidate_offset)?;
let probable_f32_le = probable_normal_f32_string(value)?;
Some(SmpLocomotivePolicyFloatAlignmentCandidate {
grounded_field_name: (*field_name).to_string(),
grounded_field_runtime_object_offset: *runtime_object_offset,
grounded_field_runtime_object_offset_hex: format!("0x{runtime_object_offset:04x}"),
grounded_field_file_offset: *file_offset,
grounded_field_file_offset_hex: format!("0x{file_offset:04x}"),
candidate_offset,
candidate_offset_hex: format!("0x{candidate_offset:04x}"),
candidate_value: value,
candidate_value_hex: format!("0x{value:08x}"),
probable_f32_le,
})
})
.collect::<Vec<_>>();
let mut evidence = vec![
format!(
"locomotive-policy neighborhood spans file offsets 0x{LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET:04x}..0x{LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET:04x}"
),
"this neighborhood covers the selected-year bucket companion scalar, two startup-reset-owned bands, the linked-site removal gate, the three locomotive-availability policy bytes, the station-list selected-station mirror, and the cached available-locomotive rating".to_string(),
"the exact byte policy lanes live at 0x0f78 and 0x0f7c..0x0f7e, while the earlier grounded dword starts map to 0x0f87, 0x0f93, and 0x0f97 and the later grounded dword starts map to 0x0f9f and 0x0fa3".to_string(),
];
if three_byte_early_float_candidates.is_empty() {
evidence.push(
"no three-byte-early little-endian float-looking starts were observed ahead of the grounded dword fields in this file".to_string(),
);
} else {
evidence.push(format!(
"observed {} float-looking 4-byte starts exactly three bytes before grounded dword fields in this file",
three_byte_early_float_candidates.len()
));
}
Some(SmpLocomotivePolicyNeighborhoodProbe {
profile_family,
source_kind,
window_offset: LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET,
window_end_offset: LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET,
window_len: LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET
- LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET,
window_len_hex: format!(
"0x{:x}",
LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET - LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET
),
grounded_field_observations,
three_byte_early_float_candidates,
evidence,
})
}
fn parse_pre_recipe_scalar_plateau_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpPreRecipeScalarPlateauProbe> {
special_conditions_probe?;
if PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET > bytes.len() {
return None;
}
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "pre-recipe-scalar-plateau",
"gms" => "pre-recipe-scalar-plateau",
"gmx" => "pre-recipe-scalar-plateau",
_ => "pre-recipe-scalar-plateau",
}
.to_string();
let aligned_dword_count =
(PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET - PRE_RECIPE_SCALAR_PLATEAU_OFFSET) / 4;
let mut nonzero_lanes = Vec::new();
for index in 0..aligned_dword_count {
let absolute_offset = PRE_RECIPE_SCALAR_PLATEAU_OFFSET + index * 4;
let value = read_u32_at(bytes, absolute_offset)?;
if value == 0 {
continue;
}
nonzero_lanes.push(SmpPreRecipeScalarPlateauLane {
absolute_offset,
relative_offset: absolute_offset - PRE_RECIPE_SCALAR_PLATEAU_OFFSET,
absolute_offset_hex: format!("0x{absolute_offset:04x}"),
relative_offset_hex: format!(
"0x{:x}",
absolute_offset - PRE_RECIPE_SCALAR_PLATEAU_OFFSET
),
value,
value_hex: format!("0x{value:08x}"),
probable_f32_le: probable_normal_f32_string(value),
});
}
let family_signature = match (
read_u32_at(bytes, 0x0faf),
read_u32_at(bytes, 0x0fb3),
read_u32_at(bytes, 0x0fcb),
) {
(Some(0x4000003f), Some(0xe560423f), Some(0x00000000)) => {
"rt3-105-scenario-pre-recipe-plateau-v1"
}
(Some(0x8000003f), Some(0x75c28f3f), Some(0x00300000)) => {
"rt3-105-base-pre-recipe-plateau-v1"
}
(Some(0x8000003f), Some(0x75c28f3f), Some(0xcdcdcd00)) => {
"rt3-105-alt-pre-recipe-plateau-v1"
}
_ => "unknown",
}
.to_string();
let mut evidence = vec![
format!(
"aligned scalar plateau spans file offsets 0x{PRE_RECIPE_SCALAR_PLATEAU_OFFSET:04x}..0x{PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET:04x}"
),
"this plateau ends immediately before the grounded recipe-book root at [world+0x0fe7]".to_string(),
"current grounding inside this span is still structural rather than semantic, so the probe only records aligned dword lanes and observed family signatures".to_string(),
];
if !nonzero_lanes.is_empty() {
evidence.push(format!(
"observed {} nonzero aligned dword lanes in the pre-recipe plateau",
nonzero_lanes.len()
));
}
if family_signature != "unknown" {
evidence.push(format!(
"matched observed family signature {family_signature}"
));
}
Some(SmpPreRecipeScalarPlateauProbe {
profile_family,
source_kind,
window_offset: PRE_RECIPE_SCALAR_PLATEAU_OFFSET,
window_end_offset: PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET,
window_len: PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET - PRE_RECIPE_SCALAR_PLATEAU_OFFSET,
window_len_hex: format!(
"0x{:x}",
PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET - PRE_RECIPE_SCALAR_PLATEAU_OFFSET
),
aligned_dword_count,
family_signature,
nonzero_lanes,
evidence,
})
}
fn parse_recipe_book_summary_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpRecipeBookSummaryProbe> {
special_conditions_probe?;
if RECIPE_BOOK_SUMMARY_END_OFFSET > bytes.len() {
return None;
}
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "recipe-book-summary",
"gms" => "recipe-book-summary",
"gmx" => "recipe-book-summary",
_ => "recipe-book-summary",
}
.to_string();
let mut books = Vec::with_capacity(RECIPE_BOOK_COUNT);
let mut mixed_head_count = 0usize;
let mut mixed_line_area_count = 0usize;
let mut cdcd_line_area_count = 0usize;
let mut zero_line_area_count = 0usize;
for book_index in 0..RECIPE_BOOK_COUNT {
let book_offset = RECIPE_BOOK_ROOT_OFFSET + book_index * RECIPE_BOOK_STRIDE;
let head = &bytes[book_offset..book_offset + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET];
let line_area_offset = book_offset + RECIPE_BOOK_LINE_AREA_OFFSET;
let line_area = &bytes[line_area_offset..line_area_offset + RECIPE_BOOK_LINE_AREA_LEN];
let max_annual_production_offset = book_offset + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET;
let max_annual_production_word = read_u32_at(bytes, max_annual_production_offset)?;
let mut lines = Vec::with_capacity(RECIPE_BOOK_LINE_COUNT);
for line_index in 0..RECIPE_BOOK_LINE_COUNT {
let line_offset = line_area_offset + line_index * RECIPE_BOOK_LINE_STRIDE;
let line = &bytes[line_offset..line_offset + RECIPE_BOOK_LINE_STRIDE];
let supplied_cargo_token_window = &line[0x08..0x20];
let demanded_cargo_token_window = &line[0x1c..0x30];
let mode_word = read_u32_at(bytes, line_offset)?;
let annual_amount_word = read_u32_at(bytes, line_offset + 0x04)?;
let supplied_cargo_token_word = read_u32_at(bytes, line_offset + 0x08)?;
let demanded_cargo_token_word = read_u32_at(bytes, line_offset + 0x1c)?;
lines.push(SmpRecipeBookLineSummary {
line_index,
line_offset,
line_offset_hex: format!("0x{line_offset:04x}"),
line_kind: classify_recipe_book_region_kind(line).to_string(),
line_signature_kind: classify_recipe_line_signature(
mode_word,
supplied_cargo_token_word,
demanded_cargo_token_word,
)
.to_string(),
imports_to_runtime_descriptor: mode_word != 0,
runtime_import_branch_kind: classify_recipe_runtime_import_branch(mode_word)
.to_string(),
line_nonzero_byte_count: line.iter().filter(|byte| **byte != 0).count(),
line_cdcd_byte_count: line.iter().filter(|byte| **byte == 0xcd).count(),
line_first_16_hex: hex_encode(&line[..RECIPE_BOOK_HEAD_SAMPLE_LEN.min(line.len())]),
mode_word_offset: line_offset,
mode_word_offset_hex: format!("0x{line_offset:04x}"),
mode_word,
mode_word_hex: format!("0x{mode_word:08x}"),
annual_amount_offset: line_offset + 0x04,
annual_amount_offset_hex: format!("0x{:04x}", line_offset + 0x04),
annual_amount_word,
annual_amount_word_hex: format!("0x{annual_amount_word:08x}"),
annual_amount_probable_f32_le: probable_normal_f32_string(annual_amount_word),
supplied_cargo_token_offset: line_offset + 0x08,
supplied_cargo_token_offset_hex: format!("0x{:04x}", line_offset + 0x08),
supplied_cargo_token_word,
supplied_cargo_token_word_hex: format!("0x{supplied_cargo_token_word:08x}"),
supplied_cargo_token_layout_kind: classify_recipe_token_layout(
supplied_cargo_token_word,
)
.to_string(),
supplied_cargo_token_window_hex: hex_encode(supplied_cargo_token_window),
supplied_cargo_token_window_ascii: ascii_preview(supplied_cargo_token_window),
supplied_cargo_token_active_in_runtime_import: mode_word != 0 && mode_word != 1,
supplied_cargo_token_probable_high16_ascii_stem:
probable_recipe_token_high16_ascii_stem(supplied_cargo_token_word),
demanded_cargo_token_offset: line_offset + 0x1c,
demanded_cargo_token_offset_hex: format!("0x{:04x}", line_offset + 0x1c),
demanded_cargo_token_word,
demanded_cargo_token_word_hex: format!("0x{demanded_cargo_token_word:08x}"),
demanded_cargo_token_layout_kind: classify_recipe_token_layout(
demanded_cargo_token_word,
)
.to_string(),
demanded_cargo_token_window_hex: hex_encode(demanded_cargo_token_window),
demanded_cargo_token_window_ascii: ascii_preview(demanded_cargo_token_window),
demanded_cargo_token_active_in_runtime_import: mode_word == 1 || mode_word == 3,
demanded_cargo_token_probable_high16_ascii_stem:
probable_recipe_token_high16_ascii_stem(demanded_cargo_token_word),
});
}
let head_kind = classify_recipe_book_region_kind(head).to_string();
let line_area_kind = classify_recipe_book_region_kind(line_area).to_string();
if head_kind == "mixed" {
mixed_head_count += 1;
}
match line_area_kind.as_str() {
"zero" => zero_line_area_count += 1,
"cdcd" => cdcd_line_area_count += 1,
_ => mixed_line_area_count += 1,
}
books.push(SmpRecipeBookSummaryBook {
book_index,
book_offset,
book_offset_hex: format!("0x{book_offset:04x}"),
head_kind,
head_nonzero_byte_count: head.iter().filter(|byte| **byte != 0).count(),
head_cdcd_byte_count: head.iter().filter(|byte| **byte == 0xcd).count(),
head_first_16_hex: hex_encode(&head[..RECIPE_BOOK_HEAD_SAMPLE_LEN.min(head.len())]),
max_annual_production_offset,
max_annual_production_offset_hex: format!("0x{max_annual_production_offset:04x}"),
max_annual_production_word,
max_annual_production_word_hex: format!("0x{max_annual_production_word:08x}"),
max_annual_production_probable_f32_le: probable_normal_f32_string(
max_annual_production_word,
),
line_area_offset,
line_area_offset_hex: format!("0x{line_area_offset:04x}"),
line_area_len: RECIPE_BOOK_LINE_AREA_LEN,
line_area_len_hex: format!("0x{:x}", RECIPE_BOOK_LINE_AREA_LEN),
line_area_kind,
line_area_nonzero_byte_count: line_area.iter().filter(|byte| **byte != 0).count(),
line_area_cdcd_byte_count: line_area.iter().filter(|byte| **byte == 0xcd).count(),
line_area_first_16_hex: hex_encode(
&line_area[..RECIPE_BOOK_HEAD_SAMPLE_LEN.min(line_area.len())],
),
lines,
});
}
let mut evidence = vec![
format!(
"grounded recipe-book root begins at file offset 0x{RECIPE_BOOK_ROOT_OFFSET:04x} and runtime offset [world+0x{RECIPE_BOOK_ROOT_OFFSET:04x}]"
),
format!(
"parsed {RECIPE_BOOK_COUNT} fixed books with stride 0x{RECIPE_BOOK_STRIDE:x}, shared cap lane at +0x{RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET:x}, and five line slots at +0x{RECIPE_BOOK_LINE_AREA_OFFSET:x} with stride 0x{RECIPE_BOOK_LINE_STRIDE:x}"
),
"this probe is structural only: it summarizes per-book heads plus five raw line records without decoding the mode or cargo-token semantics beyond the grounded offsets".to_string(),
];
evidence.push(format!(
"{mixed_head_count} books have mixed pre-line heads; line areas split into {zero_line_area_count} zero, {cdcd_line_area_count} cdcd, and {mixed_line_area_count} mixed books"
));
Some(SmpRecipeBookSummaryProbe {
profile_family,
source_kind,
root_offset: RECIPE_BOOK_ROOT_OFFSET,
root_offset_hex: format!("0x{RECIPE_BOOK_ROOT_OFFSET:04x}"),
runtime_object_root_offset: RECIPE_BOOK_ROOT_OFFSET,
runtime_object_root_offset_hex: format!("0x{RECIPE_BOOK_ROOT_OFFSET:04x}"),
book_count: RECIPE_BOOK_COUNT,
book_stride: RECIPE_BOOK_STRIDE,
book_stride_hex: format!("0x{:x}", RECIPE_BOOK_STRIDE),
max_annual_production_relative_offset: RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET,
max_annual_production_relative_offset_hex: format!(
"0x{:x}",
RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET
),
line_area_relative_offset: RECIPE_BOOK_LINE_AREA_OFFSET,
line_area_relative_offset_hex: format!("0x{:x}", RECIPE_BOOK_LINE_AREA_OFFSET),
line_count: RECIPE_BOOK_LINE_COUNT,
line_stride: RECIPE_BOOK_LINE_STRIDE,
line_stride_hex: format!("0x{:x}", RECIPE_BOOK_LINE_STRIDE),
books,
evidence,
})
}
fn parse_smp_aligned_runtime_rule_band_probe(
bytes: &[u8],
file_extension_hint: Option<&str>,
container_profile: Option<&SmpContainerProfile>,
special_conditions_probe: Option<&SmpSpecialConditionsProbe>,
) -> Option<SmpAlignedRuntimeRuleBandProbe> {
special_conditions_probe?;
if SMP_ALIGNED_RUNTIME_RULE_END_OFFSET > bytes.len() {
return None;
}
let source_kind = match file_extension_hint.unwrap_or("") {
"gmp" => "map-smp-aligned-runtime-rule-band",
"gms" => "save-smp-aligned-runtime-rule-band",
"gmx" => "sandbox-smp-aligned-runtime-rule-band",
_ => "smp-aligned-runtime-rule-band",
}
.to_string();
let profile_family = container_profile
.map(|profile| profile.profile_family.clone())
.unwrap_or_else(|| "unknown".to_string());
let mut nonzero_lanes = Vec::new();
for band_index in 0..SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT {
let absolute_offset = SPECIAL_CONDITIONS_OFFSET + band_index * 4;
let value = read_u32_at(bytes, absolute_offset)?;
if value == 0 {
continue;
}
let lane_kind = if band_index < SPECIAL_CONDITION_COUNT {
"known-special-condition-dword"
} else if band_index < SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT {
"unlabeled-editor-rule-dword"
} else {
"trailing-runtime-scalar"
}
.to_string();
let known_label = if band_index < SPECIAL_CONDITION_COUNT {
Some(
KNOWN_SPECIAL_CONDITION_DEFINITIONS[band_index]
.label
.to_string(),
)
} else {
None
};
nonzero_lanes.push(SmpAlignedRuntimeRuleBandLane {
band_index,
absolute_offset,
relative_offset: absolute_offset - SPECIAL_CONDITIONS_OFFSET,
absolute_offset_hex: format!("0x{absolute_offset:04x}"),
relative_offset_hex: format!("0x{:x}", absolute_offset - SPECIAL_CONDITIONS_OFFSET),
lane_kind,
known_label,
value,
value_hex: format!("0x{value:08x}"),
probable_f32_le: probable_normal_f32_string(value),
});
}
let nonzero_band_indices = nonzero_lanes
.iter()
.map(|lane| lane.band_index)
.collect::<Vec<_>>();
let nonzero_post_window_overlap_band_indices = nonzero_lanes
.iter()
.filter(|lane| {
lane.band_index >= SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
&& lane.band_index
< SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
+ SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
})
.map(|lane| lane.band_index)
.collect::<Vec<_>>();
let nonzero_post_window_overlap_post_relative_offset_hexes = nonzero_lanes
.iter()
.filter(|lane| {
lane.band_index >= SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
&& lane.band_index
< SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
+ SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
})
.map(|lane| {
format!(
"0x{:x}",
(lane.band_index - SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX) * 4
)
})
.collect::<Vec<_>>();
let nonzero_relative_offset_hexes = nonzero_lanes
.iter()
.map(|lane| lane.relative_offset_hex.clone())
.collect::<Vec<_>>();
let mut evidence = vec![
format!(
"fixed `.smp`-aligned runtime-rule band at 0x{SPECIAL_CONDITIONS_OFFSET:04x}..0x{SMP_ALIGNED_RUNTIME_RULE_END_OFFSET:04x}"
),
format!(
"band spans {} known editor rule dwords plus one trailing scalar",
SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT
),
"first 36 dwords overlap the older fixed matrix probe rooted at 0x0d64".to_string(),
format!(
"trailing band indices {}..{} alias the leading post-sentinel window offsets {}..{}",
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX,
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
+ SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
- 1,
"0x00",
format!(
"0x{:x}",
(SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT - 1) * 4
)
),
"band matches the grounded `.smp` save/load copy into `[world+0x4a7f..+0x4b43]`"
.to_string(),
];
if nonzero_lanes.is_empty() {
evidence
.push("all dwords in the aligned runtime-rule band are zero for this file".to_string());
} else {
evidence.push(format!(
"observed {} nonzero lanes at band indices {:?}",
nonzero_lanes.len(),
nonzero_band_indices
));
if !nonzero_post_window_overlap_band_indices.is_empty() {
evidence.push(format!(
"nonzero overlap lanes mirror post-window offsets {:?}",
nonzero_post_window_overlap_post_relative_offset_hexes
));
}
}
Some(SmpAlignedRuntimeRuleBandProbe {
profile_family,
source_kind,
band_offset: SPECIAL_CONDITIONS_OFFSET,
band_end_offset: SMP_ALIGNED_RUNTIME_RULE_END_OFFSET,
band_len: SMP_ALIGNED_RUNTIME_RULE_END_OFFSET - SPECIAL_CONDITIONS_OFFSET,
band_len_hex: format!(
"0x{:x}",
SMP_ALIGNED_RUNTIME_RULE_END_OFFSET - SPECIAL_CONDITIONS_OFFSET
),
dword_count: SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT,
known_editor_rule_dword_count: SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT,
trailing_scalar_index: SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1,
trailing_scalar_offset: SPECIAL_CONDITIONS_OFFSET
+ (SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1) * 4,
trailing_scalar_offset_hex: format!(
"0x{:04x}",
SPECIAL_CONDITIONS_OFFSET + (SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT - 1) * 4
),
post_window_overlap_start_index: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX,
post_window_overlap_dword_count: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT,
post_window_overlap_end_index: SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
+ SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
- 1,
post_window_overlap_post_relative_offset_start_hex: "0x0".to_string(),
post_window_overlap_post_relative_offset_end_hex: format!(
"0x{:x}",
(SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT - 1) * 4
),
nonzero_post_window_overlap_band_indices,
nonzero_post_window_overlap_post_relative_offset_hexes,
nonzero_lane_count: nonzero_lanes.len(),
nonzero_band_indices,
nonzero_relative_offset_hexes,
nonzero_lanes,
evidence,
})
}
fn matches_candidate_availability_table_header(bytes: &[u8], header_offset: usize) -> bool {
matches!(
(
read_u32_at(bytes, header_offset + 0x08),
read_u32_at(bytes, header_offset + 0x0c),
read_u32_at(bytes, header_offset + 0x10),
read_u32_at(bytes, header_offset + 0x14),
read_u32_at(bytes, header_offset + 0x18),
read_u32_at(bytes, header_offset + 0x1c),
read_u32_at(bytes, header_offset + 0x20),
read_u32_at(bytes, header_offset + 0x24),
read_u32_at(bytes, header_offset + 0x28),
),
(
Some(0x0000332e),
Some(0x00000001),
Some(0x00000022),
Some(0x00000002),
Some(0x00000002),
Some(_),
Some(_),
Some(0x00000000),
Some(0x00000001),
)
)
}
fn classify_name_table_footer_progress_alignment(value: u32) -> Option<&'static str> {
match value {
0x32dc => Some(
"Footer progress word 0x000032dc matches the grounded late rehydrate progress id 0x32dc.",
),
0x3714 => Some(
"Footer progress word 0x00003714 matches the grounded late rehydrate progress id 0x3714.",
),
_ => None,
}
}
fn parse_rt3_105_packed_profile_block(
bytes: &[u8],
packed_profile_offset: usize,
packed_profile_len: usize,
) -> Option<SmpRt3105PackedProfileBlock> {
let block_end = packed_profile_offset.checked_add(packed_profile_len)?;
if block_end > bytes.len() || packed_profile_len != 0x108 {
return None;
}
let leading_word_0 = read_u32_at(bytes, packed_profile_offset)?;
let trailing_zero_word_count_after_leading_word = (1..4)
.take_while(|index| {
read_u32_at(bytes, packed_profile_offset + (index * 4)).is_some_and(|word| word == 0)
})
.count();
let header_flag_word_3 = read_u32_at(bytes, packed_profile_offset + 0x0c)?;
let map_path_offset = 0x10usize;
let display_name_offset = 0x43usize;
let stable_nonzero_word_offsets = [0x00usize, 0x0c, 0x78, 0x7c, 0x80, 0x84];
let stable_nonzero_words = stable_nonzero_word_offsets
.iter()
.filter_map(|relative_offset| {
let value = read_u32_at(bytes, packed_profile_offset + relative_offset)?;
if value == 0 {
return None;
}
Some(SmpPackedProfileWordLane {
relative_offset: *relative_offset,
relative_offset_hex: format!("0x{relative_offset:02x}"),
value,
value_hex: format!("0x{value:08x}"),
})
})
.collect::<Vec<_>>();
Some(SmpRt3105PackedProfileBlock {
relative_len: packed_profile_len,
relative_len_hex: format!("0x{packed_profile_len:03x}"),
leading_word_0,
leading_word_0_hex: format!("0x{leading_word_0:08x}"),
trailing_zero_word_count_after_leading_word,
header_flag_word_3,
header_flag_word_3_hex: format!("0x{header_flag_word_3:08x}"),
map_path_offset,
map_path: read_c_string_in_range(bytes, packed_profile_offset + map_path_offset, block_end),
display_name_offset,
display_name: read_c_string_in_range(
bytes,
packed_profile_offset + display_name_offset,
block_end,
),
profile_byte_0x77: bytes[packed_profile_offset + 0x77],
profile_byte_0x77_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x77]),
profile_byte_0x82: bytes[packed_profile_offset + 0x82],
profile_byte_0x82_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x82]),
profile_byte_0x97: bytes[packed_profile_offset + 0x97],
profile_byte_0x97_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0x97]),
profile_byte_0xc5: bytes[packed_profile_offset + 0xc5],
profile_byte_0xc5_hex: format!("0x{:02x}", bytes[packed_profile_offset + 0xc5]),
stable_nonzero_words,
})
}
fn collect_runtime_post_span_header_candidates(
bytes: &[u8],
start: usize,
search_len: usize,
) -> Vec<SmpRuntimePostSpanHeaderCandidate> {
let end = bytes.len().min(start + search_len);
let mut offset = start & !0x3;
let mut candidates = Vec::new();
while offset + 16 <= end && candidates.len() < 8 {
if let Some(candidate) = build_runtime_post_span_header_candidate(bytes, offset) {
let mut cluster_end = offset + 4;
while cluster_end + 16 <= end
&& build_runtime_post_span_header_candidate(bytes, cluster_end).is_some()
{
cluster_end += 4;
}
candidates.push(candidate);
offset = cluster_end;
} else {
offset += 4;
}
}
candidates
}
fn build_runtime_post_span_header_candidate(
bytes: &[u8],
offset: usize,
) -> Option<SmpRuntimePostSpanHeaderCandidate> {
let words = read_u32_window(bytes, offset, 4);
if words.len() < 4 {
return None;
}
let dense_words = words
.iter()
.copied()
.filter(|word| (word & 0xffff) == 0 && (word >> 16) != 0)
.collect::<Vec<_>>();
if dense_words.len() < 3 {
return None;
}
let high_u16_words = words
.iter()
.map(|word| (word >> 16) as u16)
.collect::<Vec<_>>();
let mut grounded_alignments = Vec::new();
for high in &high_u16_words {
if let Some(alignment) = classify_runtime_post_span_high16_grounded_alignment(*high) {
if !grounded_alignments
.iter()
.any(|existing| existing == alignment)
{
grounded_alignments.push(alignment.to_string());
}
}
}
Some(SmpRuntimePostSpanHeaderCandidate {
offset,
hex_words: words.iter().map(|word| format!("0x{word:08x}")).collect(),
dense_word_count: dense_words.len(),
high_hex_words: high_u16_words
.iter()
.map(|word| format!("0x{word:04x}"))
.collect(),
high_u16_words,
grounded_alignments,
words,
})
}
fn classify_runtime_post_span_high16_grounded_alignment(high_u16: u16) -> Option<&'static str> {
match high_u16 {
0x32dc => Some(
"High-16 value 0x32dc matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
),
0x3714 => Some(
"High-16 value 0x3714 matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
),
0x3715 => Some(
"High-16 value 0x3715 matches the grounded late rehydrate progress id posted during world_entry_transition_and_runtime_bringup.",
),
_ => None,
}
}
fn find_grounded_progress_high16_hits(
bytes: &[u8],
start: usize,
search_len: usize,
) -> Vec<String> {
let end = bytes.len().min(start + search_len);
let mut hits = Vec::new();
let mut offset = start & !0x3;
while offset + 4 <= end {
if let Some(word) = read_u32_at(bytes, offset) {
let high = (word >> 16) as u16;
if matches!(high, 0x32dc | 0x3714 | 0x3715) {
hits.push(format!("0x{high:04x}@0x{offset:08x}"));
}
}
offset += 4;
}
hits
}
fn parse_grounded_progress_hit_offset(hits: &[String], high_u16: u16) -> Option<usize> {
let needle = format!("0x{high_u16:04x}@0x");
let hit = hits.iter().find(|hit| hit.starts_with(&needle))?;
let offset_hex = hit.split("@0x").nth(1)?;
usize::from_str_radix(offset_hex, 16).ok()
}
fn collect_ascii_previews_in_range(
bytes: &[u8],
start: usize,
end: usize,
min_len: usize,
) -> Vec<SmpAsciiPreview> {
let mut previews = Vec::new();
let mut run_start = None;
let end = end.min(bytes.len());
for index in start..end {
let byte = bytes[index];
if is_ascii_preview_byte(byte) {
run_start.get_or_insert(index);
continue;
}
if let Some(current_start) = run_start.take() {
if index - current_start >= min_len {
previews.push(build_ascii_preview(bytes, current_start, index));
}
}
}
if let Some(current_start) = run_start {
if end - current_start >= min_len {
previews.push(build_ascii_preview(bytes, current_start, end));
}
}
previews
}
fn find_c_string_with_suffix_in_range(
bytes: &[u8],
start: usize,
end: usize,
suffix: &str,
) -> Option<usize> {
let end = end.min(bytes.len());
let suffix = suffix.as_bytes();
let mut offset = start.min(end);
while offset < end {
if !is_ascii_preview_byte(bytes[offset]) {
offset += 1;
continue;
}
let run_start = offset;
while offset < end && is_ascii_preview_byte(bytes[offset]) {
offset += 1;
}
let run = &bytes[run_start..offset];
if run.ends_with(suffix) {
return Some(run_start);
}
}
None
}
fn read_c_string_in_range(bytes: &[u8], start: usize, end: usize) -> Option<String> {
if start >= end || start >= bytes.len() {
return None;
}
let end = end.min(bytes.len());
let mut cursor = start;
while cursor < end && bytes[cursor] != 0 {
cursor += 1;
}
if cursor == start {
return None;
}
std::str::from_utf8(&bytes[start..cursor])
.ok()
.map(ToString::to_string)
}
fn find_u16_le_offsets(bytes: &[u8], needle: u16) -> Vec<usize> {
let pattern = needle.to_le_bytes();
bytes
.windows(pattern.len())
.enumerate()
.filter_map(|(offset, window)| (window == pattern).then_some(offset))
.collect()
}
fn find_u32_le_offsets(bytes: &[u8], needle: u32) -> Vec<usize> {
let pattern = needle.to_le_bytes();
bytes
.windows(pattern.len())
.enumerate()
.filter_map(|(offset, window)| (window == pattern).then_some(offset))
.collect()
}
fn find_next_nonzero_offset(bytes: &[u8], start: usize) -> Option<usize> {
bytes
.iter()
.enumerate()
.skip(start)
.find_map(|(offset, byte)| (*byte != 0).then_some(offset))
}
fn find_zero_run(bytes: &[u8], start: usize, min_len: usize) -> Option<usize> {
let mut run_start = None;
let mut run_len = 0usize;
for (offset, byte) in bytes.iter().enumerate().skip(start) {
if *byte == 0 {
run_start.get_or_insert(offset);
run_len += 1;
if run_len >= min_len {
return run_start;
}
} else {
run_start = None;
run_len = 0;
}
}
None
}
fn find_first_ascii_run(bytes: &[u8]) -> Option<SmpAsciiPreview> {
let mut start = None;
for (index, byte) in bytes.iter().copied().enumerate() {
if is_ascii_preview_byte(byte) {
start.get_or_insert(index);
continue;
}
if let Some(run_start) = start.take() {
if index - run_start >= MIN_ASCII_RUN_LEN {
return Some(build_ascii_preview(bytes, run_start, index));
}
}
}
start.and_then(|run_start| {
if bytes.len() - run_start >= MIN_ASCII_RUN_LEN {
Some(build_ascii_preview(bytes, run_start, bytes.len()))
} else {
None
}
})
}
fn build_ascii_preview(bytes: &[u8], start: usize, end: usize) -> SmpAsciiPreview {
let byte_len = end - start;
let preview_bytes = &bytes[start..end];
let preview = String::from_utf8_lossy(
&preview_bytes[..preview_bytes.len().min(ASCII_PREVIEW_CHAR_LIMIT)],
)
.into_owned();
SmpAsciiPreview {
offset: start,
byte_len,
truncated: byte_len > ASCII_PREVIEW_CHAR_LIMIT,
preview,
}
}
fn is_ascii_preview_byte(byte: u8) -> bool {
matches!(byte, b' ' | b'\t' | b'\n' | b'\r' | 0x21..=0x7e)
}
fn read_u32_window(bytes: &[u8], offset: usize, count: usize) -> Vec<u32> {
let mut words = Vec::new();
let end = bytes.len().min(offset + count * 4);
for chunk in bytes[offset..end].chunks_exact(4) {
words.push(u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]));
}
words
}
fn read_u8_at(bytes: &[u8], offset: usize) -> Option<u8> {
bytes.get(offset).copied()
}
fn read_u16_at(bytes: &[u8], offset: usize) -> Option<u16> {
let chunk = bytes.get(offset..offset + 2)?;
Some(u16::from_le_bytes([chunk[0], chunk[1]]))
}
fn read_u32_at(bytes: &[u8], offset: usize) -> Option<u32> {
let chunk = bytes.get(offset..offset + 4)?;
Some(u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]))
}
fn read_i32_at(bytes: &[u8], offset: usize) -> Option<i32> {
let chunk = bytes.get(offset..offset + 4)?;
Some(i32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]))
}
fn read_i64_at(bytes: &[u8], offset: usize) -> Option<i64> {
let chunk = bytes.get(offset..offset + 8)?;
Some(i64::from_le_bytes([
chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7],
]))
}
fn read_u64_at(bytes: &[u8], offset: usize) -> Option<u64> {
let chunk = bytes.get(offset..offset + 8)?;
Some(u64::from_le_bytes([
chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7],
]))
}
fn read_f32_at(bytes: &[u8], offset: usize) -> Option<f32> {
let chunk = bytes.get(offset..offset + 4)?;
Some(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]))
}
fn read_f64_at(bytes: &[u8], offset: usize) -> Option<f64> {
let chunk = bytes.get(offset..offset + 8)?;
Some(f64::from_le_bytes([
chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7],
]))
}
fn read_ascii_c_string_at(bytes: &[u8], offset: usize, max_len: usize) -> Option<String> {
let chunk = bytes.get(offset..offset + max_len)?;
let nul_index = chunk.iter().position(|byte| *byte == 0).unwrap_or(max_len);
let text = std::str::from_utf8(&chunk[..nul_index])
.ok()?
.trim()
.to_string();
Some(text)
}
fn parse_nonzero_u32(bytes: &[u8], offset: usize) -> Option<Option<u32>> {
read_u32_at(bytes, offset).map(|value| (value != 0).then_some(value))
}
fn round_f64_to_i64(value: f64) -> Option<i64> {
if !value.is_finite() {
return None;
}
let rounded = value.round();
if rounded < i64::MIN as f64 || rounded > i64::MAX as f64 {
return None;
}
Some(rounded as i64)
}
fn probable_normal_f32_string(value: u32) -> Option<String> {
let exponent = (value >> 23) & 0xff;
if exponent == 0 || exponent == 0xff {
return None;
}
let scalar = f32::from_bits(value);
if !scalar.is_finite() {
return None;
}
Some(format!("{scalar:.6}"))
}
fn probable_recipe_token_high16_ascii_stem(value: u32) -> Option<String> {
if value & 0xffff != 0 {
return None;
}
let high = ((value >> 16) & 0xffff) as u16;
if high == 0 {
return None;
}
let low_byte = (high & 0x00ff) as u8;
let high_byte = (high >> 8) as u8;
if !low_byte.is_ascii_alphabetic() || !high_byte.is_ascii_alphabetic() {
return None;
}
Some(format!("{}{}", low_byte as char, high_byte as char))
}
fn classify_recipe_token_layout(value: u32) -> &'static str {
if value == 0 {
return "zero";
}
if probable_recipe_token_high16_ascii_stem(value).is_some() {
return "high16-ascii-stem";
}
if value & 0xffff == 0 {
return "high16-numeric";
}
if value >> 16 == 0 {
return "low16-marker";
}
"mixed"
}
fn classify_recipe_line_signature(
mode_word: u32,
supplied_cargo_token_word: u32,
demanded_cargo_token_word: u32,
) -> &'static str {
let supplied_layout = classify_recipe_token_layout(supplied_cargo_token_word);
let demanded_layout = classify_recipe_token_layout(demanded_cargo_token_word);
if mode_word == 0 && supplied_cargo_token_word == 0 && demanded_layout == "high16-numeric" {
return "demand-numeric-entry";
}
if mode_word == 0 && supplied_cargo_token_word == 0 && demanded_layout == "high16-ascii-stem" {
return "demand-stem-entry";
}
if mode_word == 0 && demanded_cargo_token_word == 0 && supplied_layout == "high16-numeric" {
return "supply-numeric-entry";
}
if mode_word != 0 && demanded_cargo_token_word == 0 && supplied_layout == "low16-marker" {
return "supply-marker-entry";
}
if mode_word == 0 && supplied_cargo_token_word == 0 && demanded_cargo_token_word == 0 {
return "zero";
}
"mixed"
}
fn classify_recipe_runtime_import_branch(mode_word: u32) -> &'static str {
if mode_word == 0 {
return "zero-mode-skipped";
}
if mode_word == 1 {
return "mode1-demand-branch";
}
if mode_word == 3 {
return "mode3-dual-branch";
}
"nonzero-supply-branch"
}
fn classify_recipe_book_region_kind(bytes: &[u8]) -> &'static str {
if bytes.iter().all(|byte| *byte == 0) {
"zero"
} else if bytes.iter().all(|byte| *byte == 0xcd) {
"cdcd"
} else {
"mixed"
}
}
fn hex_encode(bytes: &[u8]) -> String {
bytes.iter().map(|byte| format!("{byte:02x}")).collect()
}
fn ascii_preview(bytes: &[u8]) -> String {
bytes
.iter()
.map(|byte| match byte {
0x20..=0x7e => char::from(*byte),
_ => '.',
})
.collect()
}
fn sha256_hex(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
format!("{digest:x}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reports_grounded_tag_hits_and_offsets() {
let bytes = [
0x34, 0x12, 0x00, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x80,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x71, 0x07, 0x00, 0x00, 0x71, 0x07, 0x00, 0x00,
0x71, 0x07, 0x00, 0x00, 0xaa, 0xbb, 0x00, 0x00, 0xcc, 0xdd, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, b'H', b'e', b'l',
b'l', b'o', b' ', b'R', b'R', b'T', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
0x9a, 0xbc, 0xde, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xee, 0x2c, 0x11, 0x51, 0x2d, 0x22,
0x71, 0x94, 0x33, 0x72, 0x94,
];
let report = inspect_smp_bytes(&bytes);
assert!(report.contains_grounded_runtime_tags);
assert_eq!(report.known_tag_hits.len(), 4);
assert_eq!(report.preamble.word_count, 16);
assert_eq!(report.preamble.words[0].value_le, 0x00001234);
let shared_header = report
.shared_header
.as_ref()
.expect("shared header should parse");
assert!(shared_header.matches_grounded_common_signature);
let header_variant = report
.header_variant_probe
.as_ref()
.expect("header variant probe should exist");
assert_eq!(header_variant.variant_family, "unknown");
assert!(!header_variant.is_known_family);
assert_eq!(shared_header.primary_family_tag, 0x00002ee0);
assert_eq!(
shared_header.payload_window_words_8_to_9,
vec![0x0000bbaa, 0x0000ddcc]
);
assert!(shared_header.reserved_words_10_to_14_all_zero);
assert_eq!(shared_header.final_flag_word, 0);
let ascii_run = report
.first_ascii_run
.as_ref()
.expect("ascii run should exist");
assert_eq!(ascii_run.offset, 67);
assert_eq!(ascii_run.byte_len, 9);
assert_eq!(ascii_run.preview, "Hello RRT");
let early_probe = report
.early_content_probe
.as_ref()
.expect("early content probe should exist");
assert_eq!(early_probe.first_post_text_nonzero_offset, 88);
assert_eq!(early_probe.zero_pad_after_text_len, 12);
assert_eq!(early_probe.first_post_text_block_len, 4);
assert_eq!(early_probe.first_post_text_block_hex, "11223344");
assert_eq!(early_probe.trailing_zero_pad_after_first_block_len, 16);
assert_eq!(early_probe.secondary_nonzero_offset, Some(108));
assert_eq!(early_probe.secondary_aligned_word_window_offset, Some(108));
assert_eq!(
&early_probe.secondary_aligned_word_window_words[..2],
&[0x78563412, 0xf0debc9a]
);
assert!(
early_probe
.secondary_preview_hex
.starts_with("123456789abcdef0")
);
let secondary_variant = report
.secondary_variant_probe
.as_ref()
.expect("secondary variant probe should exist");
assert_eq!(secondary_variant.variant_family, "unknown");
let container_profile = report
.container_profile
.as_ref()
.expect("container profile should exist");
assert_eq!(container_profile.profile_family, "unknown");
assert!(!container_profile.is_known_profile);
assert!(report.save_bootstrap_block.is_none());
assert!(report.save_anchor_run_block.is_none());
assert!(report.runtime_anchor_cycle_block.is_none());
assert!(report.runtime_trailer_block.is_none());
assert!(report.runtime_post_span_probe.is_none());
assert!(report.classic_rehydrate_profile_probe.is_none());
assert_eq!(report.known_tag_hits[0].tag_id, 0x2cee);
assert_eq!(report.known_tag_hits[0].hit_count, 1);
assert_eq!(report.known_tag_hits[0].sample_offsets, vec![120]);
assert_eq!(report.known_tag_hits[1].tag_id, 0x2d51);
assert_eq!(report.known_tag_hits[1].sample_offsets, vec![123]);
assert_eq!(report.known_tag_hits[2].tag_id, 0x9471);
assert_eq!(report.known_tag_hits[2].sample_offsets, vec![126]);
assert_eq!(report.known_tag_hits[3].tag_id, 0x9472);
assert_eq!(report.known_tag_hits[3].sample_offsets, vec![129]);
}
#[test]
fn warns_when_no_grounded_tags_are_present() {
let report = inspect_smp_bytes(&[0xaa, 0xbb, 0xcc]);
assert!(!report.contains_grounded_runtime_tags);
assert!(report.known_tag_hits.is_empty());
assert_eq!(report.preamble.word_count, 0);
assert!(report.shared_header.is_none());
assert!(report.header_variant_probe.is_none());
assert!(report.first_ascii_run.is_none());
assert!(report.early_content_probe.is_none());
assert!(report.secondary_variant_probe.is_none());
assert!(report.container_profile.is_none());
assert!(report.save_bootstrap_block.is_none());
assert!(report.save_anchor_run_block.is_none());
assert!(report.runtime_anchor_cycle_block.is_none());
assert!(report.runtime_trailer_block.is_none());
assert!(report.runtime_post_span_probe.is_none());
assert!(report.classic_rehydrate_profile_probe.is_none());
assert!(
report
.warnings
.iter()
.any(|warning| warning.contains("No grounded runtime bundle tags were found"))
);
}
#[test]
fn parses_zeroed_post_special_conditions_scalar_window() {
let mut bytes = vec![0u8; POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gmp"), None)
.expect("special-conditions probe should parse");
let probe = parse_post_special_conditions_scalar_probe(
&bytes,
Some("gmp"),
Some(&SmpContainerProfile {
profile_family: "rt3-map-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("post-special-conditions probe should parse");
assert_eq!(probe.window_offset, POST_SPECIAL_CONDITIONS_SCALAR_OFFSET);
assert_eq!(
probe.window_end_offset,
POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
);
assert_eq!(probe.dword_count, 79);
assert_eq!(
probe.overlap_end_offset,
POST_SPECIAL_CONDITIONS_SCALAR_OVERLAP_END_OFFSET
);
assert_eq!(probe.overlap_dword_count, 14);
assert_eq!(probe.overlap_nonzero_dword_count, 0);
assert!(probe.overlap_nonzero_relative_offset_hexes.is_empty());
assert_eq!(
probe.tail_offset,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_OFFSET
);
assert_eq!(probe.tail_dword_count, 65);
assert_eq!(
probe.tail_runtime_object_offset,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_OFFSET
);
assert_eq!(
probe.tail_runtime_object_end_offset,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_RUNTIME_OBJECT_END_OFFSET
);
assert!(!probe.tail_runtime_object_validated_byte_mirror);
assert_eq!(
probe.tail_grounded_live_field_offset,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_OFFSET
);
assert_eq!(
probe.tail_grounded_live_field_copy_len,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_LEN
);
assert_eq!(
probe.tail_grounded_live_field_copy_end_offset,
POST_SPECIAL_CONDITIONS_SCALAR_TAIL_GROUNDED_TEXT_FIELD_COPY_END_OFFSET
);
assert!(probe.tail_window_cuts_through_grounded_live_field);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_offset,
POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET
);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_len,
0x28
);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_nonzero_byte_count,
0
);
assert_eq!(probe.tail_next_grounded_dword_field_offset_hex, "0x4c80");
assert_eq!(
probe.tail_next_grounded_dword_field_file_offset_hex,
"0x0f65"
);
assert_eq!(probe.tail_second_grounded_dword_field_offset_hex, "0x4c8c");
assert_eq!(
probe.tail_second_grounded_dword_field_file_offset_hex,
"0x0f71"
);
assert!(!probe.post_text_field_file_alignment_matches_grounded_dword_fields);
assert!(
probe
.tail_grounded_live_field_remaining_file_window_first_nonzero_offset
.is_none()
);
assert!(
probe
.tail_grounded_live_field_remaining_file_window_last_nonzero_offset
.is_none()
);
assert_eq!(probe.tail_nonzero_dword_count, 0);
assert!(probe.tail_first_nonzero_offset.is_none());
assert!(probe.tail_last_nonzero_offset.is_none());
assert!(probe.tail_nonzero_relative_offset_hexes.is_empty());
assert_eq!(probe.nonzero_dword_count, 0);
assert!(probe.first_nonzero_offset.is_none());
assert!(probe.last_nonzero_offset.is_none());
assert!(probe.nonzero_lanes.is_empty());
}
#[test]
fn parses_zeroed_smp_aligned_runtime_rule_band() {
let mut bytes = vec![0u8; POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gmp"), None)
.expect("special-conditions probe should parse");
let probe = parse_smp_aligned_runtime_rule_band_probe(
&bytes,
Some("gmp"),
Some(&SmpContainerProfile {
profile_family: "rt3-map-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("aligned runtime-rule band probe should parse");
assert_eq!(probe.band_offset, SPECIAL_CONDITIONS_OFFSET);
assert_eq!(probe.band_end_offset, SMP_ALIGNED_RUNTIME_RULE_END_OFFSET);
assert_eq!(probe.dword_count, SMP_ALIGNED_RUNTIME_RULE_DWORD_COUNT);
assert_eq!(
probe.known_editor_rule_dword_count,
SMP_ALIGNED_RUNTIME_RULE_KNOWN_EDITOR_RULE_COUNT
);
assert_eq!(
probe.post_window_overlap_start_index,
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_START_INDEX
);
assert_eq!(
probe.post_window_overlap_dword_count,
SMP_ALIGNED_RUNTIME_RULE_POST_WINDOW_OVERLAP_DWORD_COUNT
);
assert_eq!(probe.nonzero_lane_count, 1);
assert_eq!(probe.nonzero_band_indices, vec![35]);
assert!(probe.nonzero_post_window_overlap_band_indices.is_empty());
assert!(
probe
.nonzero_post_window_overlap_post_relative_offset_hexes
.is_empty()
);
assert_eq!(
probe.nonzero_lanes[0].lane_kind,
"known-special-condition-dword"
);
assert_eq!(
probe.nonzero_lanes[0].known_label.as_deref(),
Some("Hidden sentinel")
);
}
#[test]
fn parses_nonzero_post_special_conditions_scalar_window() {
let mut bytes = vec![0u8; POST_SPECIAL_CONDITIONS_GROUNDED_TEXT_FIELD_FILE_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
bytes[0x0df8..0x0dfc].copy_from_slice(&0x413d298cu32.to_le_bytes());
bytes[0x0e00..0x0e04].copy_from_slice(&0x40e6b756u32.to_le_bytes());
bytes[0x0f0c..0x0f10].copy_from_slice(&0x42574909u32.to_le_bytes());
bytes[0x0f34] = 0xaa;
bytes[0x0f4e] = 0xbb;
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gms"), None)
.expect("special-conditions probe should parse");
let probe = parse_post_special_conditions_scalar_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("post-special-conditions probe should parse");
assert_eq!(probe.nonzero_dword_count, 3);
assert_eq!(probe.first_nonzero_offset, Some(0x0df8));
assert_eq!(probe.last_nonzero_offset, Some(0x0f0c));
assert_eq!(probe.overlap_nonzero_dword_count, 2);
assert_eq!(
probe.overlap_nonzero_relative_offset_hexes,
vec!["0x4".to_string(), "0xc".to_string()]
);
assert_eq!(probe.tail_nonzero_dword_count, 1);
assert_eq!(probe.tail_first_nonzero_offset, Some(0x0f0c));
assert_eq!(probe.tail_last_nonzero_offset, Some(0x0f0c));
assert_eq!(
probe.tail_nonzero_relative_offset_hexes,
vec!["0x118".to_string()]
);
assert_eq!(probe.tail_runtime_object_offset_hex, "0x4b47");
assert_eq!(probe.tail_runtime_object_end_offset_hex, "0x4c4b");
assert_eq!(
probe.tail_grounded_live_field_copy_end_offset_hex,
"0x4c73".to_string()
);
assert_eq!(
probe.tail_grounded_live_field_name,
"victory-or-outcome status text buffer"
);
assert!(probe.tail_window_cuts_through_grounded_live_field);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_len_hex,
"0x28"
);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_nonzero_byte_count,
2
);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_first_nonzero_offset,
Some(0x0f34)
);
assert_eq!(
probe.tail_grounded_live_field_remaining_file_window_last_nonzero_offset,
Some(0x0f4e)
);
assert_eq!(probe.tail_next_grounded_dword_field_file_offset, 0x0f65);
assert_eq!(probe.tail_second_grounded_dword_field_file_offset, 0x0f71);
assert!(!probe.post_text_field_file_alignment_matches_grounded_dword_fields);
assert_eq!(probe.nonzero_lanes[0].relative_offset, 0x04);
assert_eq!(probe.nonzero_lanes[1].relative_offset, 0x0c);
assert_eq!(probe.nonzero_lanes[2].relative_offset, 0x118);
assert!(
probe
.nonzero_lanes
.iter()
.all(|lane| lane.probable_f32_le.is_some())
);
}
#[test]
fn parses_post_text_field_neighborhood_probe() {
let mut bytes = vec![0u8; POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
bytes[0x0f59] = 0x01;
bytes[0x0f5d] = 0x02;
bytes[0x0f61] = 0x03;
bytes[0x0f6d] = 0x04;
bytes[0x0f5c..0x0f60].copy_from_slice(&0x40f33333u32.to_le_bytes());
bytes[0x0f6c..0x0f70].copy_from_slice(&0x40c08cfbu32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gms"), None)
.expect("special-conditions probe should parse");
let probe = parse_post_text_field_neighborhood_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("post-text field neighborhood probe should parse");
assert_eq!(probe.window_offset, POST_TEXT_FIELD_NEIGHBORHOOD_OFFSET);
assert_eq!(
probe.window_end_offset,
POST_TEXT_FIELD_NEIGHBORHOOD_END_OFFSET
);
assert_eq!(probe.grounded_field_observations.len(), 6);
assert_eq!(
probe.grounded_field_observations[0].field_name,
"Auto-Show Grade During Track Lay"
);
assert_eq!(probe.grounded_field_observations[0].value_u8, Some(0x01));
assert_eq!(
probe.grounded_field_observations[3].field_name,
"leftover simulation time accumulator"
);
assert_eq!(probe.one_byte_early_float_candidates.len(), 2);
assert_eq!(
probe.one_byte_early_float_candidates[0].grounded_field_name,
"Starting Building Density Level"
);
assert_eq!(
probe.one_byte_early_float_candidates[0].candidate_offset_hex,
"0x0f5c"
);
assert_eq!(
probe.one_byte_early_float_candidates[1].grounded_field_name,
"selected-year lane snapshot"
);
assert_eq!(
probe.one_byte_early_float_candidates[1].candidate_offset_hex,
"0x0f6c"
);
}
#[test]
fn parses_locomotive_policy_neighborhood_probe() {
let mut bytes = vec![0u8; LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
bytes[0x0f78] = 0x01;
bytes[0x0f7c] = 0x02;
bytes[0x0f7d] = 0x03;
bytes[0x0f7e] = 0x04;
bytes[0x0f9c..0x0fa0].copy_from_slice(&0x42c1c036u32.to_le_bytes());
bytes[0x0fa0..0x0fa4].copy_from_slice(&0x433a7abeu32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gms"), None)
.expect("special-conditions probe should parse");
let probe = parse_locomotive_policy_neighborhood_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("locomotive policy neighborhood probe should parse");
assert_eq!(probe.window_offset, LOCOMOTIVE_POLICY_NEIGHBORHOOD_OFFSET);
assert_eq!(
probe.window_end_offset,
LOCOMOTIVE_POLICY_NEIGHBORHOOD_END_OFFSET
);
assert_eq!(probe.grounded_field_observations.len(), 9);
assert_eq!(
probe.grounded_field_observations[0].field_name,
"selected-year bucket companion scalar"
);
assert_eq!(
probe.grounded_field_observations[4].field_name,
"All Steam Locos Avail."
);
assert_eq!(probe.grounded_field_observations[4].value_u8, Some(0x02));
assert_eq!(
probe.grounded_field_observations[8].field_name,
"cached available-locomotive rating"
);
assert_eq!(probe.three_byte_early_float_candidates.len(), 2);
assert_eq!(
probe.three_byte_early_float_candidates[0].grounded_field_name,
"station-list selected station id"
);
assert_eq!(
probe.three_byte_early_float_candidates[0].candidate_offset_hex,
"0x0f9c"
);
assert_eq!(
probe.three_byte_early_float_candidates[1].grounded_field_name,
"cached available-locomotive rating"
);
assert_eq!(
probe.three_byte_early_float_candidates[1].candidate_offset_hex,
"0x0fa0"
);
}
#[test]
fn parses_pre_recipe_scalar_plateau_probe() {
let mut bytes = vec![0u8; PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
bytes[0x0fa7..0x0fab].copy_from_slice(&0x82839300u32.to_le_bytes());
bytes[0x0fab..0x0faf].copy_from_slice(&0x948c9949u32.to_le_bytes());
bytes[0x0faf..0x0fb3].copy_from_slice(&0x8000003fu32.to_le_bytes());
bytes[0x0fb3..0x0fb7].copy_from_slice(&0x75c28f3fu32.to_le_bytes());
bytes[0x0fcb..0x0fcf].copy_from_slice(&0x00300000u32.to_le_bytes());
bytes[0x0fdb..0x0fdf].copy_from_slice(&0x00ffea22u32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gms"), None)
.expect("special-conditions probe should parse");
let probe = parse_pre_recipe_scalar_plateau_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("pre-recipe scalar plateau probe should parse");
assert_eq!(probe.window_offset, PRE_RECIPE_SCALAR_PLATEAU_OFFSET);
assert_eq!(
probe.window_end_offset,
PRE_RECIPE_SCALAR_PLATEAU_END_OFFSET
);
assert_eq!(probe.family_signature, "rt3-105-base-pre-recipe-plateau-v1");
assert_eq!(probe.nonzero_lanes[0].absolute_offset_hex, "0x0fa7");
assert_eq!(probe.nonzero_lanes[2].absolute_offset_hex, "0x0faf");
assert_eq!(probe.nonzero_lanes[2].value_hex, "0x8000003f");
}
#[test]
fn parses_recipe_book_summary_probe() {
let mut bytes = vec![0u8; RECIPE_BOOK_SUMMARY_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
let book0 = RECIPE_BOOK_ROOT_OFFSET;
bytes[book0..book0 + 16].copy_from_slice(&[
0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
0x70, 0x80,
]);
bytes[book0 + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET
..book0 + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET + 4]
.copy_from_slice(&0x41200000u32.to_le_bytes());
bytes[book0 + RECIPE_BOOK_LINE_AREA_OFFSET
..book0 + RECIPE_BOOK_LINE_AREA_OFFSET + RECIPE_BOOK_LINE_AREA_LEN]
.fill(0xcd);
bytes[book0 + RECIPE_BOOK_LINE_AREA_OFFSET..book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 4]
.copy_from_slice(&0x00000003u32.to_le_bytes());
bytes[book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 4..book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 8]
.copy_from_slice(&0x41a00000u32.to_le_bytes());
bytes[book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 8..book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 12]
.copy_from_slice(&0x00000017u32.to_le_bytes());
bytes[book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 0x1c
..book0 + RECIPE_BOOK_LINE_AREA_OFFSET + 0x20]
.copy_from_slice(&0x0000002au32.to_le_bytes());
let book1 = RECIPE_BOOK_ROOT_OFFSET + RECIPE_BOOK_STRIDE;
bytes[book1 + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET
..book1 + RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET + 4]
.copy_from_slice(&0x00000000u32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gmp"), None)
.expect("special-conditions probe should parse");
let probe = parse_recipe_book_summary_probe(
&bytes,
Some("gmp"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-map-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("recipe-book summary probe should parse");
assert_eq!(probe.root_offset, RECIPE_BOOK_ROOT_OFFSET);
assert_eq!(probe.book_count, RECIPE_BOOK_COUNT);
assert_eq!(probe.book_stride, RECIPE_BOOK_STRIDE);
assert_eq!(
probe.max_annual_production_relative_offset,
RECIPE_BOOK_MAX_ANNUAL_PRODUCTION_OFFSET
);
assert_eq!(probe.books[0].head_kind, "mixed");
assert_eq!(probe.books[0].line_area_kind, "mixed");
assert_eq!(probe.books[0].max_annual_production_word_hex, "0x41200000");
assert_eq!(
probe.books[0]
.max_annual_production_probable_f32_le
.as_deref(),
Some("10.000000")
);
assert_eq!(probe.books[0].lines.len(), RECIPE_BOOK_LINE_COUNT);
assert_eq!(probe.books[0].lines[0].line_kind, "mixed");
assert_eq!(probe.books[0].lines[0].mode_word_hex, "0x00000003");
assert_eq!(probe.books[0].lines[0].annual_amount_word_hex, "0x41a00000");
assert_eq!(
probe.books[0].lines[0]
.annual_amount_probable_f32_le
.as_deref(),
Some("20.000000")
);
assert_eq!(
probe.books[0].lines[0].supplied_cargo_token_word_hex,
"0x00000017"
);
assert_eq!(
probe.books[0].lines[0].supplied_cargo_token_window_hex,
"17000000cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd2a000000"
);
assert_eq!(
probe.books[0].lines[0].supplied_cargo_token_window_ascii,
"....................*..."
);
assert!(probe.books[0].lines[0].supplied_cargo_token_active_in_runtime_import);
assert_eq!(
probe.books[0].lines[0].demanded_cargo_token_word_hex,
"0x0000002a"
);
assert_eq!(
probe.books[0].lines[0].demanded_cargo_token_window_hex,
"2a000000cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
);
assert_eq!(
probe.books[0].lines[0].demanded_cargo_token_window_ascii,
"*..................."
);
assert!(probe.books[0].lines[0].demanded_cargo_token_active_in_runtime_import);
assert_eq!(probe.books[1].head_kind, "zero");
assert_eq!(probe.books[1].line_area_kind, "zero");
assert_eq!(probe.books[1].lines[0].line_kind, "zero");
}
#[test]
fn decodes_probable_recipe_token_high16_ascii_stem() {
assert_eq!(
probable_recipe_token_high16_ascii_stem(0x72470000).as_deref(),
Some("Gr")
);
assert_eq!(
probable_recipe_token_high16_ascii_stem(0x68430000).as_deref(),
Some("Ch")
);
assert_eq!(probable_recipe_token_high16_ascii_stem(0x000040a0), None);
assert_eq!(probable_recipe_token_high16_ascii_stem(0x00170000), None);
}
#[test]
fn classifies_recipe_token_layouts() {
assert_eq!(classify_recipe_token_layout(0x00000000), "zero");
assert_eq!(
classify_recipe_token_layout(0x72470000),
"high16-ascii-stem"
);
assert_eq!(classify_recipe_token_layout(0x00170000), "high16-numeric");
assert_eq!(classify_recipe_token_layout(0x000040a0), "low16-marker");
}
#[test]
fn classifies_recipe_line_signatures() {
assert_eq!(
classify_recipe_line_signature(0x00000000, 0x00000000, 0x00010000),
"demand-numeric-entry"
);
assert_eq!(
classify_recipe_line_signature(0x00000000, 0x00000000, 0x72470000),
"demand-stem-entry"
);
assert_eq!(
classify_recipe_line_signature(0x00000000, 0x00170000, 0x00000000),
"supply-numeric-entry"
);
assert_eq!(
classify_recipe_line_signature(0x00110000, 0x000040a0, 0x00000000),
"supply-marker-entry"
);
}
#[test]
fn classifies_recipe_runtime_import_branches() {
assert_eq!(
classify_recipe_runtime_import_branch(0),
"zero-mode-skipped"
);
assert_eq!(
classify_recipe_runtime_import_branch(1),
"mode1-demand-branch"
);
assert_eq!(
classify_recipe_runtime_import_branch(3),
"mode3-dual-branch"
);
assert_eq!(
classify_recipe_runtime_import_branch(0x00110000),
"nonzero-supply-branch"
);
}
#[test]
fn parses_nonzero_smp_aligned_runtime_rule_band() {
let mut bytes = vec![0u8; POST_SPECIAL_CONDITIONS_SCALAR_END_OFFSET];
let sentinel_offset =
SPECIAL_CONDITIONS_OFFSET + SPECIAL_CONDITION_HIDDEN_SENTINEL_SLOT * 4;
bytes[sentinel_offset..sentinel_offset + 4].copy_from_slice(&1u32.to_le_bytes());
bytes[0x0df8..0x0dfc].copy_from_slice(&0x413d298cu32.to_le_bytes());
bytes[0x0e00..0x0e04].copy_from_slice(&0x40e6b756u32.to_le_bytes());
bytes[0x0e18..0x0e1c].copy_from_slice(&0x41d4ccceu32.to_le_bytes());
bytes[0x0e24..0x0e28].copy_from_slice(&0x3fd2b549u32.to_le_bytes());
let special_conditions_probe = parse_special_conditions_probe(&bytes, Some("gms"), None)
.expect("special-conditions probe should parse");
let probe = parse_smp_aligned_runtime_rule_band_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&special_conditions_probe),
)
.expect("aligned runtime-rule band probe should parse");
assert_eq!(probe.nonzero_band_indices, vec![35, 37, 39, 45, 48]);
assert_eq!(
probe.nonzero_post_window_overlap_band_indices,
vec![37, 39, 45, 48]
);
assert_eq!(
probe.nonzero_post_window_overlap_post_relative_offset_hexes,
vec![
"0x4".to_string(),
"0xc".to_string(),
"0x24".to_string(),
"0x30".to_string()
]
);
assert_eq!(probe.nonzero_lanes[1].relative_offset, 0x94);
assert_eq!(
probe.nonzero_lanes[1].lane_kind,
"unlabeled-editor-rule-dword"
);
assert!(probe.nonzero_lanes[1].probable_f32_le.is_some());
assert_eq!(probe.nonzero_lanes.last().unwrap().band_index, 48);
}
#[test]
fn parses_save_anchor_cycle_and_trailer() {
let cycle_words: [u32; 9] = [
0x00000000, 0x0186a000, 0x00000000, 0x86a00000, 0x00000001, 0xa0000000, 0x00000186,
0x00000000, 0x000186a0,
];
let trailer_words: [u32; 3] = [0x00020000, 0x00030000, 0x2ee10000];
let mut bytes = vec![0u8; 0x1c + (cycle_words.len() * 2 + 2 + trailer_words.len()) * 4];
let mut cursor = 0x1c;
for _ in 0..2 {
for word in cycle_words {
bytes[cursor..cursor + 4].copy_from_slice(&word.to_le_bytes());
cursor += 4;
}
}
for word in &cycle_words[..2] {
bytes[cursor..cursor + 4].copy_from_slice(&(*word).to_le_bytes());
cursor += 4;
}
for word in trailer_words {
bytes[cursor..cursor + 4].copy_from_slice(&word.to_le_bytes());
cursor += 4;
}
let container_profile = SmpContainerProfile {
profile_family: "rt3-classic-save-container-v1".to_string(),
profile_evidence: vec!["test".to_string()],
is_known_profile: true,
};
let bootstrap = SmpSaveBootstrapBlock {
profile_family: "rt3-classic-save-container-v1".to_string(),
aligned_window_offset: 0,
leading_word: 0,
leading_word_hex: "0x00000000".to_string(),
anchor_word: 0,
anchor_word_hex: "0x00000000".to_string(),
descriptor_word_2: 0,
descriptor_word_2_hex: "0x00000000".to_string(),
descriptor_word_3: 0,
descriptor_word_3_hex: "0x00000000".to_string(),
descriptor_word_4: 0,
descriptor_word_4_hex: "0x00000000".to_string(),
descriptor_word_5: 0,
descriptor_word_5_hex: "0x00000000".to_string(),
descriptor_word_6: 0,
descriptor_word_6_hex: "0x00000000".to_string(),
descriptor_word_7: 0,
descriptor_word_7_hex: "0x00000000".to_string(),
};
let parsed =
parse_save_anchor_run_block(&bytes, Some(&container_profile), Some(&bootstrap))
.expect("cycle block should parse");
assert_eq!(parsed.cycle_start_offset, 0x1c);
assert_eq!(parsed.cycle_words, cycle_words);
assert_eq!(parsed.full_cycle_count, 2);
assert_eq!(parsed.partial_cycle_word_count, 2);
assert_eq!(
parsed.trailer_offset,
0x1c + (cycle_words.len() * 2 + 2) * 4
);
assert_eq!(parsed.trailer_words, trailer_words);
}
#[test]
fn classifies_runtime_trailer_family() {
let runtime_anchor_cycle_block = SmpRuntimeAnchorCycleBlock {
profile_family: "rt3-classic-sandbox-container-v1".to_string(),
cycle_start_offset: 0x33c,
cycle_words: vec![0; 9],
cycle_hex_words: vec!["0x00000000".to_string(); 9],
full_cycle_count: 3,
partial_cycle_word_count: 2,
trailer_offset: 0x3b0,
trailer_words: vec![
0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00000000, 0x00000000, 0x2ee10000,
0x32c80000, 0x0dcd0000, 0x01010107, 0x26010000, 0x01010107, 0x00010000, 0x0334c68c,
0x03000000, 0x01000000,
],
trailer_hex_words: Vec::new(),
};
let container_profile = SmpContainerProfile {
profile_family: "rt3-classic-sandbox-container-v1".to_string(),
profile_evidence: vec!["test".to_string()],
is_known_profile: true,
};
let trailer = parse_runtime_trailer_block(
Some(&container_profile),
Some(&runtime_anchor_cycle_block),
)
.expect("runtime trailer should parse");
assert_eq!(trailer.trailer_family, "rt3-classic-sandbox-trailer-v1");
assert_eq!(trailer.prefix_words_0_to_5[0], 0x00010000);
assert_eq!(trailer.tag_word_6, 0x2ee10000);
assert_eq!(trailer.tag_chunk_id_u16, 0x2ee1);
assert_eq!(trailer.selector_word_8, 0x0dcd0000);
assert_eq!(trailer.selector_high_u16, 0x0dcd);
assert_eq!(trailer.mode_word_15, 0x01000000);
}
#[test]
fn probes_runtime_post_span_region() {
let mut bytes = vec![0u8; 0x200];
bytes[0x90..0x94].copy_from_slice(&0x32dc0000u32.to_le_bytes());
bytes[0x94..0x98].copy_from_slice(&0x37140000u32.to_le_bytes());
bytes[0x98..0x9c].copy_from_slice(&0x03000000u32.to_le_bytes());
bytes[0xa0..0xa4].copy_from_slice(&0x37150000u32.to_le_bytes());
bytes[0xa4..0xa8].copy_from_slice(&0x00010000u32.to_le_bytes());
bytes[0xa8..0xac].copy_from_slice(&0x00410000u32.to_le_bytes());
let trailer = SmpRuntimeTrailerBlock {
profile_family: "rt3-classic-save-container-v1".to_string(),
trailer_family: "test".to_string(),
trailer_evidence: Vec::new(),
trailer_offset: 0x40,
prefix_words_0_to_5: Vec::new(),
prefix_hex_words_0_to_5: Vec::new(),
tag_word_6: 0x2ee10000,
tag_word_6_hex: "0x2ee10000".to_string(),
tag_chunk_id_u16: 0x2ee1,
tag_chunk_id_hex: "0x2ee1".to_string(),
tag_chunk_id_grounded_alignment: None,
length_word_7: 0x00200000,
length_word_7_hex: "0x00200000".to_string(),
length_high_u16: 0x0020,
length_high_hex: "0x0020".to_string(),
selector_word_8: 0,
selector_word_8_hex: "0x00000000".to_string(),
selector_high_u16: 0,
selector_high_hex: "0x0000".to_string(),
layout_word_9: 0,
layout_word_9_hex: "0x00000000".to_string(),
descriptor_word_10: 0,
descriptor_word_10_hex: "0x00000000".to_string(),
descriptor_high_u16: 0,
descriptor_high_hex: "0x0000".to_string(),
descriptor_word_11: 0,
descriptor_word_11_hex: "0x00000000".to_string(),
counter_word_12: 0,
counter_word_12_hex: "0x00000000".to_string(),
offset_word_13: 0,
offset_word_13_hex: "0x00000000".to_string(),
span_word_14: 0,
span_word_14_hex: "0x00000000".to_string(),
mode_word_15: 0,
mode_word_15_hex: "0x00000000".to_string(),
words: Vec::new(),
hex_words: Vec::new(),
};
let probe = parse_runtime_post_span_probe(&bytes, Some(&trailer))
.expect("post-span probe should parse");
assert_eq!(probe.span_target_offset, 0x60);
assert_eq!(probe.next_nonzero_offset, Some(0x92));
assert_eq!(probe.next_aligned_candidate_offset, Some(0x8c));
assert_eq!(probe.header_candidates.len(), 1);
assert_eq!(probe.header_candidates[0].dense_word_count, 3);
assert_eq!(probe.header_candidates[0].grounded_alignments.len(), 2);
assert_eq!(probe.grounded_progress_hits[0], "0x32dc@0x00000090");
}
#[test]
fn parses_classic_rehydrate_profile_probe() {
let mut bytes = vec![0u8; 0x220];
bytes[0x90..0x94].copy_from_slice(&0x32dc0000u32.to_le_bytes());
bytes[0x94..0x98].copy_from_slice(&0x37140000u32.to_le_bytes());
bytes[0x1a0..0x1a4].copy_from_slice(&0x37150000u32.to_le_bytes());
bytes[0xab..0xb7].copy_from_slice(b"test-map.gmp");
bytes[0xde..0xe6].copy_from_slice(b"Test Map");
let post_span = SmpRuntimePostSpanProbe {
profile_family: "rt3-classic-save-container-v1".to_string(),
span_target_offset: 0,
next_nonzero_offset: Some(0x92),
next_aligned_candidate_offset: Some(0x8c),
next_aligned_candidate_words: vec![0, 0x32dc0000, 0x37140000, 0x03000000],
next_aligned_candidate_hex_words: vec![],
header_candidates: vec![],
grounded_progress_hits: vec![
"0x32dc@0x00000090".to_string(),
"0x3714@0x00000094".to_string(),
"0x3715@0x000001a0".to_string(),
],
};
let probe = parse_classic_rehydrate_profile_probe(&bytes, Some(&post_span))
.expect("classic rehydrate probe should parse");
assert_eq!(probe.packed_profile_offset, 0x98);
assert_eq!(probe.packed_profile_len, 0x108);
assert_eq!(probe.ascii_runs[0].preview, "test-map.gmp");
assert_eq!(probe.packed_profile_block.leading_word_0, 0x00000000);
assert_eq!(
probe.packed_profile_block.map_path.as_deref(),
Some("test-map.gmp")
);
assert_eq!(
probe.packed_profile_block.display_name.as_deref(),
Some("Test Map")
);
assert_eq!(probe.packed_profile_block.profile_byte_0x77, 0x00);
assert_eq!(probe.packed_profile_block.profile_byte_0x82, 0x00);
assert_eq!(probe.packed_profile_block.profile_byte_0x97, 0x00);
assert_eq!(probe.packed_profile_block.profile_byte_0xc5, 0x00);
}
#[test]
fn parses_rt3_105_packed_profile_probe() {
let mut bytes = vec![0u8; 0x9000];
let block = 0x73c0usize;
bytes[block..block + 4].copy_from_slice(&0x00000003u32.to_le_bytes());
bytes[block + 0x0c..block + 0x10].copy_from_slice(&0x01000000u32.to_le_bytes());
bytes[block + 0x10..block + 0x1d].copy_from_slice(b"test-105.gmp\0");
bytes[block + 0x43..block + 0x4c].copy_from_slice(b"Test 105\0");
bytes[block + 0x77] = 0x07;
bytes[block + 0x82] = 0x4d;
bytes[block + 0x84..block + 0x88].copy_from_slice(&0x65010000u32.to_le_bytes());
let header_variant_probe = SmpHeaderVariantProbe {
variant_family: "rt3-105-common-header-v1".to_string(),
variant_evidence: vec![],
is_known_family: true,
};
let probe = parse_rt3_105_packed_profile_probe(
&bytes,
Some("gms"),
Some(&header_variant_probe),
None,
)
.expect("1.05 packed profile probe should parse");
assert_eq!(probe.profile_family, "rt3-105-save-analog-block-inferred");
assert_eq!(probe.packed_profile_offset, 0x73c0);
assert_eq!(probe.packed_profile_len, 0x108);
assert_eq!(
probe.packed_profile_block.map_path.as_deref(),
Some("test-105.gmp")
);
assert_eq!(
probe.packed_profile_block.display_name.as_deref(),
Some("Test 105")
);
assert_eq!(probe.packed_profile_block.profile_byte_0x77, 0x07);
assert_eq!(probe.packed_profile_block.profile_byte_0x82, 0x4d);
assert_eq!(probe.packed_profile_block.profile_byte_0x97, 0x00);
assert_eq!(probe.packed_profile_block.profile_byte_0xc5, 0x00);
}
#[test]
fn builds_classic_save_load_summary() {
let summary = build_save_load_summary(
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-classic-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
None,
Some(&SmpClassicRehydrateProfileProbe {
profile_family: "rt3-classic-save-container-v1".to_string(),
progress_32dc_offset: 0x76e8,
progress_3714_offset: 0x76ec,
progress_3715_offset: 0x77f8,
packed_profile_offset: 0x76f0,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpClassicPackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 3,
map_path_offset: 0x13,
map_path: Some("British Isles.gmp".to_string()),
display_name_offset: 0x46,
display_name: Some("British Isles".to_string()),
profile_byte_0x77: 0,
profile_byte_0x77_hex: "0x00".to_string(),
profile_byte_0x82: 0,
profile_byte_0x82_hex: "0x00".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
}),
None,
None,
)
.expect("classic summary");
assert_eq!(summary.mechanism_family, "classic-save-rehydrate-v1");
assert_eq!(summary.mechanism_confidence, "grounded");
assert_eq!(summary.map_path.as_deref(), Some("British Isles.gmp"));
assert_eq!(summary.packed_profile_len, Some(0x108));
}
#[test]
fn builds_rt3_105_save_load_summary_with_candidate_table() {
let summary = build_save_load_summary(
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
Some(&SmpRt3105PostSpanBridgeProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
bridge_family: "rt3-105-save-post-span-bridge-v1".to_string(),
bridge_evidence: vec![],
span_target_offset: 0x3678,
next_candidate_offset: Some(0x4f14),
next_candidate_delta_from_span_target: Some(0x189c),
packed_profile_offset: 0x73c0,
packed_profile_delta_from_span_target: 0x3d48,
next_candidate_delta_from_packed_profile: Some(-0x24ac),
selector_high_u16: 0x7110,
selector_high_hex: "0x7110".to_string(),
descriptor_high_u16: 0x7801,
descriptor_high_hex: "0x7801".to_string(),
next_candidate_high_u16_words: vec![0x6200, 0x0000, 0xfff7, 0x5515],
next_candidate_high_hex_words: vec![],
}),
None,
Some(&SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
packed_profile_offset: 0x73c0,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 2,
header_flag_word_3: 1,
header_flag_word_3_hex: "0x00000001".to_string(),
map_path_offset: 0x10,
map_path: Some("Alternate USA.gmp".to_string()),
display_name_offset: 0x43,
display_name: Some("Alternate USA".to_string()),
profile_byte_0x77: 0x07,
profile_byte_0x77_hex: "0x07".to_string(),
profile_byte_0x82: 0x4d,
profile_byte_0x82_hex: "0x4d".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
}),
Some(&SmpRt3105SaveNameTableProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-bridge-secondary-block".to_string(),
semantic_family: "scenario-named-candidate-availability-table".to_string(),
semantic_alignment: vec![],
header_offset: 0x6a70,
header_word_0: 0,
header_word_0_hex: "0x00000000".to_string(),
header_word_1: 0,
header_word_1_hex: "0x00000000".to_string(),
header_word_2: 0x332e,
header_word_2_hex: "0x0000332e".to_string(),
entry_stride: 0x22,
entry_stride_hex: "0x22".to_string(),
header_prefix_word_count: 11,
observed_entry_capacity: 0x44,
observed_entry_count: 67,
zero_trailer_entry_count: 3,
nonzero_trailer_entry_count: 64,
distinct_trailer_words: vec![0, 1],
distinct_trailer_hex_words: vec![
"0x00000000".to_string(),
"0x00000001".to_string(),
],
zero_trailer_entry_names: vec![
"Nuclear Power Plant".to_string(),
"Recycling Plant".to_string(),
"Uranium Mine".to_string(),
],
entries_offset: 0x6ad1,
entries_end_offset: 0x73b7,
trailing_footer_hex: "dc3200001437000000".to_string(),
footer_progress_word_0: 0x32dc,
footer_progress_word_0_hex: "0x000032dc".to_string(),
footer_progress_word_1: 0x3714,
footer_progress_word_1_hex: "0x00003714".to_string(),
footer_trailing_byte: 0,
footer_trailing_byte_hex: "0x00".to_string(),
footer_grounded_alignments: vec![],
entries: vec![],
evidence: vec![],
}),
)
.expect("1.05 summary");
assert_eq!(summary.mechanism_family, "rt3-105-save-post-span-bridge-v1");
assert_eq!(summary.mechanism_confidence, "mixed");
assert_eq!(summary.map_path.as_deref(), Some("Alternate USA.gmp"));
assert_eq!(
summary
.candidate_table
.as_ref()
.expect("candidate table")
.zero_availability_count,
3
);
}
#[test]
fn loads_classic_save_slice_from_report() {
let mut report = inspect_smp_bytes(&[]);
let classic_probe = SmpClassicRehydrateProfileProbe {
profile_family: "rt3-classic-save-container-v1".to_string(),
progress_32dc_offset: 0x76e8,
progress_3714_offset: 0x76ec,
progress_3715_offset: 0x77f8,
packed_profile_offset: 0x76f0,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpClassicPackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 3,
map_path_offset: 0x13,
map_path: Some("British Isles.gmp".to_string()),
display_name_offset: 0x46,
display_name: Some("British Isles".to_string()),
profile_byte_0x77: 0,
profile_byte_0x77_hex: "0x00".to_string(),
profile_byte_0x82: 0,
profile_byte_0x82_hex: "0x00".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
};
report.classic_rehydrate_profile_probe = Some(classic_probe.clone());
report.save_load_summary = build_save_load_summary(
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-classic-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
None,
Some(&classic_probe),
None,
None,
);
let slice = load_save_slice_from_report(&report).expect("classic save slice");
assert_eq!(slice.mechanism_family, "classic-save-rehydrate-v1");
assert_eq!(
slice
.profile
.as_ref()
.and_then(|profile| profile.map_path.as_deref()),
Some("British Isles.gmp")
);
assert!(slice.candidate_availability_table.is_none());
}
#[test]
fn parses_event_runtime_collection_summary_from_synthetic_chunks() {
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x14, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&[0x11, 0x22, 0x33, 0x44]);
bytes.extend_from_slice(&[0x55, 0x66, 0x77, 0x88]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&[0xde, 0xad, 0xbe, 0xef]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.packed_state_version, 0x3e9);
assert_eq!(summary.live_id_bound, 5);
assert_eq!(summary.live_record_count, 3);
assert_eq!(summary.live_entry_ids, vec![1, 3, 5]);
assert_eq!(summary.records_tag_offset, 96);
assert_eq!(summary.decoded_record_count, 0);
assert_eq!(summary.records.len(), 3);
assert_eq!(summary.records[0].decode_status, "unsupported_framing");
}
fn encode_len_prefixed_string(text: &str) -> Vec<u8> {
let mut bytes = Vec::with_capacity(1 + text.len());
bytes.push(text.len() as u8);
bytes.extend_from_slice(text.as_bytes());
bytes
}
fn encode_template(
record_id: u32,
trigger_kind: u8,
flags: u8,
actions: &[Vec<u8>],
) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(PACKED_EVENT_RECORD_TEMPLATE_SYNTHETIC_MAGIC);
bytes.extend_from_slice(&record_id.to_le_bytes());
bytes.push(trigger_kind);
bytes.push(flags);
bytes.push(actions.len() as u8);
bytes.push(0);
for action in actions {
bytes.extend_from_slice(action);
}
bytes
}
fn encode_action_set_world_flag(key: &str, value: bool) -> Vec<u8> {
let mut bytes = vec![0x01];
bytes.extend_from_slice(&encode_len_prefixed_string(key));
bytes.push(u8::from(value));
bytes
}
fn encode_action_set_special_condition(label: &str, value: u32) -> Vec<u8> {
let mut bytes = vec![0x05];
bytes.extend_from_slice(&encode_len_prefixed_string(label));
bytes.extend_from_slice(&value.to_le_bytes());
bytes
}
fn encode_action_adjust_company_cash_ids(ids: &[u32], delta: i64) -> Vec<u8> {
let mut bytes = vec![0x02, 0x01, ids.len() as u8];
for id in ids {
bytes.extend_from_slice(&id.to_le_bytes());
}
bytes.extend_from_slice(&delta.to_le_bytes());
bytes
}
fn encode_action_append_template(template: Vec<u8>) -> Vec<u8> {
let mut bytes = vec![0x06];
bytes.extend_from_slice(&(template.len() as u32).to_le_bytes());
bytes.extend_from_slice(&template);
bytes
}
fn build_synthetic_event_record(
trigger_kind: u8,
flags: u8,
standalone_count: u8,
grouped_counts: [u8; 4],
text_bands: [&[u8]; 6],
actions: &[Vec<u8>],
) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(PACKED_EVENT_RECORD_SYNTHETIC_MAGIC);
bytes.push(trigger_kind);
bytes.push(flags);
bytes.push(standalone_count);
bytes.push(actions.len() as u8);
bytes.extend_from_slice(&grouped_counts);
for band in text_bands {
bytes.extend_from_slice(&(band.len() as u16).to_le_bytes());
bytes.extend_from_slice(band);
}
for action in actions {
bytes.extend_from_slice(action);
}
bytes
}
fn encode_real_optional_string(text: &str) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&(text.len() as u16).to_le_bytes());
bytes.extend_from_slice(text.as_bytes());
bytes
}
fn build_real_condition_row(
raw_condition_id: i32,
subtype: u8,
flag_seed: u8,
candidate_name: Option<&str>,
) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&(raw_condition_id as u32).to_le_bytes());
bytes.push(subtype);
while bytes.len() < PACKED_EVENT_REAL_CONDITION_ROW_LEN {
bytes.push(flag_seed.wrapping_add(bytes.len() as u8));
}
match candidate_name {
Some(text) => bytes.extend_from_slice(&encode_real_optional_string(text)),
None => bytes.extend_from_slice(&0u16.to_le_bytes()),
}
bytes
}
fn build_real_condition_row_with_threshold(
raw_condition_id: i32,
subtype: u8,
threshold: i32,
candidate_name: Option<&str>,
) -> Vec<u8> {
let mut bytes = build_real_condition_row(raw_condition_id, subtype, 0, candidate_name);
bytes[5..9].copy_from_slice(&threshold.to_le_bytes());
bytes
}
struct RealGroupedEffectRowSpec<'a> {
descriptor_id: u32,
opcode: u8,
raw_scalar_value: i32,
value_byte_0x09: u8,
value_dword_0x0d: u32,
value_byte_0x11: u8,
value_byte_0x12: u8,
value_word_0x14: u16,
value_word_0x16: u16,
locomotive_name: Option<&'a str>,
}
fn build_real_grouped_effect_row(spec: RealGroupedEffectRowSpec<'_>) -> Vec<u8> {
let mut bytes = vec![0; PACKED_EVENT_REAL_GROUPED_EFFECT_ROW_LEN];
bytes[0..4].copy_from_slice(&spec.descriptor_id.to_le_bytes());
bytes[4..8].copy_from_slice(&(spec.raw_scalar_value as u32).to_le_bytes());
bytes[8] = spec.opcode;
bytes[9] = spec.value_byte_0x09;
bytes[0x0d..0x11].copy_from_slice(&spec.value_dword_0x0d.to_le_bytes());
bytes[0x11] = spec.value_byte_0x11;
bytes[0x12] = spec.value_byte_0x12;
bytes[0x14..0x16].copy_from_slice(&spec.value_word_0x14.to_le_bytes());
bytes[0x16..0x18].copy_from_slice(&spec.value_word_0x16.to_le_bytes());
match spec.locomotive_name {
Some(text) => bytes.extend_from_slice(&encode_real_optional_string(text)),
None => bytes.extend_from_slice(&0u16.to_le_bytes()),
}
bytes
}
#[derive(Clone, Copy)]
struct RealCompactControlSpec {
mode_byte_0x7ef: u8,
primary_selector_0x7f0: u32,
grouped_mode_0x7f4: u8,
one_shot_header_0x7f5: u32,
modifier_flag_0x7f9: u8,
modifier_flag_0x7fa: u8,
grouped_target_scope_ordinals_0x7fb: [u8; PACKED_EVENT_REAL_GROUP_COUNT],
grouped_scope_checkboxes_0x7ff: [u8; PACKED_EVENT_REAL_GROUP_COUNT],
summary_toggle_0x800: u8,
grouped_territory_selectors_0x80f: [i32; PACKED_EVENT_REAL_GROUP_COUNT],
}
fn build_real_compact_control(spec: RealCompactControlSpec) -> Vec<u8> {
let mut bytes = Vec::with_capacity(PACKED_EVENT_REAL_COMPACT_CONTROL_LEN);
bytes.push(spec.mode_byte_0x7ef);
bytes.extend_from_slice(&spec.primary_selector_0x7f0.to_le_bytes());
bytes.push(spec.grouped_mode_0x7f4);
bytes.extend_from_slice(&spec.one_shot_header_0x7f5.to_le_bytes());
bytes.push(spec.modifier_flag_0x7f9);
bytes.push(spec.modifier_flag_0x7fa);
bytes.extend_from_slice(&spec.grouped_target_scope_ordinals_0x7fb);
bytes.extend_from_slice(&spec.grouped_scope_checkboxes_0x7ff);
bytes.push(spec.summary_toggle_0x800);
for selector in spec.grouped_territory_selectors_0x80f {
bytes.extend_from_slice(&selector.to_le_bytes());
}
bytes
}
fn build_real_event_record(
text_bands: [&[u8]; 6],
compact_control: Option<RealCompactControlSpec>,
condition_rows: &[Vec<u8>],
grouped_rows: [&[Vec<u8>]; 4],
) -> Vec<u8> {
let mut bytes = Vec::new();
for band in text_bands {
bytes.extend_from_slice(&(band.len() as u16).to_le_bytes());
bytes.extend_from_slice(band);
}
if let Some(spec) = compact_control {
bytes.extend_from_slice(&build_real_compact_control(spec));
}
bytes.extend_from_slice(&PACKED_EVENT_REAL_CONDITION_MARKER.to_le_bytes());
bytes.extend_from_slice(&(condition_rows.len() as u16).to_le_bytes());
for row in condition_rows {
bytes.extend_from_slice(row);
}
bytes.extend_from_slice(&PACKED_EVENT_REAL_GROUPED_EFFECT_MARKER.to_le_bytes());
for rows in grouped_rows {
bytes.extend_from_slice(&(rows.len() as u16).to_le_bytes());
}
for rows in grouped_rows {
for row in rows {
bytes.extend_from_slice(row);
}
}
bytes
}
#[test]
fn parses_synthetic_event_runtime_record_summaries_and_actions() {
let append_template = encode_template(
99,
0x0a,
0x01,
&[encode_action_set_special_condition("Imported Follow-On", 1)],
);
let record_body = build_synthetic_event_record(
7,
0x03,
1,
[0, 1, 0, 0],
[b"Alpha", b"", b"", b"", b"", b""],
&[
encode_action_set_world_flag("from_packed_root", true),
encode_action_append_template(append_template),
],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(PACKED_EVENT_RECORDS_SYNTHETIC_MAGIC);
bytes.extend_from_slice(&(record_body.len() as u32).to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.decoded_record_count, 1);
assert_eq!(summary.imported_runtime_record_count, 1);
assert_eq!(summary.records.len(), 1);
assert_eq!(summary.records[0].decode_status, "executable");
assert_eq!(summary.records[0].payload_family, "synthetic_harness");
assert_eq!(summary.records[0].text_bands[0].preview, "Alpha");
assert_eq!(summary.records[0].standalone_condition_row_count, 1);
assert_eq!(
summary.records[0].grouped_effect_row_counts,
vec![0, 1, 0, 0]
);
assert_eq!(summary.records[0].decoded_actions.len(), 2);
match &summary.records[0].decoded_actions[1] {
RuntimeEffect::AppendEventRecord { record } => {
assert_eq!(record.record_id, 99);
assert_eq!(record.trigger_kind, 0x0a);
}
other => panic!("unexpected decoded action: {other:?}"),
}
}
#[test]
fn decodes_company_targeted_synthetic_records_as_parity_only() {
let record_body = build_synthetic_event_record(
8,
0x01,
0,
[0, 0, 0, 0],
[b"", b"", b"", b"", b"", b""],
&[encode_action_adjust_company_cash_ids(&[7], 25)],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(PACKED_EVENT_RECORDS_SYNTHETIC_MAGIC);
bytes.extend_from_slice(&(record_body.len() as u32).to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.decoded_record_count, 1);
assert_eq!(summary.imported_runtime_record_count, 1);
assert_eq!(summary.records[0].decode_status, "executable");
assert_eq!(summary.records[0].payload_family, "synthetic_harness");
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn parses_real_style_event_runtime_record_with_zero_rows() {
let record_body = build_real_event_record(
[b"Alpha", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0x63,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 1,
modifier_flag_0x7f9: 1,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 1, 2, 3],
grouped_scope_checkboxes_0x7ff: [1, 0, 1, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, 10, -1, 22],
}),
&[],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.decoded_record_count, 1);
assert_eq!(summary.imported_runtime_record_count, 0);
assert_eq!(summary.records[0].decode_status, "parity_only");
assert_eq!(summary.records[0].payload_family, "real_packed_v1");
assert_eq!(summary.records[0].trigger_kind, Some(7));
assert_eq!(summary.records[0].one_shot, Some(true));
assert_eq!(
summary.records[0]
.compact_control
.as_ref()
.expect("real compact control should parse")
.primary_selector_0x7f0,
0x63
);
assert_eq!(summary.records[0].text_bands[0].preview, "Alpha");
assert_eq!(summary.records[0].standalone_condition_row_count, 0);
assert_eq!(summary.records[0].standalone_condition_rows.len(), 0);
assert!(summary.records[0].negative_sentinel_scope.is_none());
assert_eq!(
summary.records[0].grouped_effect_row_counts,
vec![0, 0, 0, 0]
);
assert_eq!(summary.records[0].grouped_effect_rows.len(), 0);
}
#[test]
fn parses_real_style_rows_and_side_strings() {
let condition_row = build_real_condition_row(-1, 4, 0x30, Some("AutoPlant"));
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 2,
opcode: 8,
raw_scalar_value: 7,
value_byte_0x09: 1,
value_dword_0x0d: 12,
value_byte_0x11: 2,
value_byte_0x12: 3,
value_word_0x14: 24,
value_word_0x16: 36,
locomotive_name: Some("Mikado"),
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"Gamma", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 6,
primary_selector_0x7f0: 0x2a,
grouped_mode_0x7f4: 1,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 2,
modifier_flag_0x7fa: 3,
grouped_target_scope_ordinals_0x7fb: [1, 4, 7, 8],
grouped_scope_checkboxes_0x7ff: [0, 1, 0, 1],
summary_toggle_0x800: 0,
grouped_territory_selectors_0x80f: [11, -1, 33, -1],
}),
&[condition_row],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.records[0].standalone_condition_rows.len(), 1);
assert_eq!(
summary.records[0]
.compact_control
.as_ref()
.expect("real compact control should parse")
.grouped_target_scope_ordinals_0x7fb,
vec![1, 4, 7, 8]
);
assert_eq!(
summary.records[0].standalone_condition_rows[0].raw_condition_id,
-1
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.candidate_name
.as_deref(),
Some("AutoPlant")
);
let negative_sentinel_scope = summary.records[0]
.negative_sentinel_scope
.as_ref()
.expect("negative-sentinel scope summary should decode");
assert_eq!(
negative_sentinel_scope.company_test_scope,
RuntimeCompanyConditionTestScope::SelectedCompanyOnly
);
assert_eq!(
negative_sentinel_scope.player_test_scope,
RuntimePlayerConditionTestScope::AiPlayersOnly
);
assert!(!negative_sentinel_scope.territory_scope_selector_is_0x63);
assert_eq!(negative_sentinel_scope.source_row_indexes, vec![0]);
assert_eq!(summary.records[0].grouped_effect_rows.len(), 1);
assert_eq!(summary.records[0].grouped_effect_rows[0].opcode, 8);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Company Cash")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0].target_mask_bits,
Some(0x01)
);
assert_eq!(
summary.records[0].grouped_effect_rows[0].row_shape,
"multivalue_scalar"
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.semantic_family
.as_deref(),
Some("multivalue_scalar")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.semantic_preview
.as_deref(),
Some("Set Company Cash to 7 with aux [2, 3, 24, 36]")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.locomotive_name
.as_deref(),
Some("Mikado")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetCompanyCash {
target: RuntimeCompanyTarget::SelectedCompany,
value: 7,
}]
);
}
#[test]
fn decodes_real_special_condition_descriptor_from_checked_in_metadata() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 108,
opcode: 3,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Use Wartime Cargos")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("special_condition_scalar")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetSpecialCondition {
label: "Use Wartime Cargos".to_string(),
value: 1,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_real_candidate_availability_descriptor_from_checked_in_metadata() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 109,
opcode: 3,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Turbo Diesel Availability")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("candidate_availability_scalar")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetCandidateAvailability {
name: "Turbo Diesel".to_string(),
value: 1,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_real_special_condition_threshold_from_checked_in_world_condition_metadata() {
let condition_row = build_real_condition_row_with_threshold(3835, 0, 1, None);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Special Condition: Use Wartime Cargos")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_state_threshold")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::SpecialConditionThreshold {
label: "Use Wartime Cargos".to_string(),
comparator: RuntimeConditionComparator::Ge,
value: 1,
}]
);
}
#[test]
fn decodes_real_candidate_availability_threshold_from_checked_in_world_condition_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID,
0,
2,
Some("Mogul"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Candidate Availability: Mogul")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::CandidateAvailabilityThreshold {
name: "Mogul".to_string(),
comparator: RuntimeConditionComparator::Ge,
value: 2,
}]
);
}
#[test]
fn decodes_real_economic_status_threshold_from_checked_in_world_condition_metadata() {
let condition_row = build_real_condition_row_with_threshold(2350, 0, 4, None);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Economic Status")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::EconomicStatusCodeThreshold {
comparator: RuntimeConditionComparator::Ge,
value: 4,
}]
);
}
#[test]
fn decodes_real_named_locomotive_availability_threshold_from_checked_in_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
4,
42,
Some("Big Boy"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Named Locomotive Availability: Big Boy")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_scalar_threshold")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
name: "Big Boy".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 42,
}]
);
}
#[test]
fn decodes_real_named_locomotive_cost_threshold_from_checked_in_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
0,
250000,
Some("Locomotive 1"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Named Locomotive Cost: Locomotive 1")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::NamedLocomotiveCostThreshold {
name: "Locomotive 1".to_string(),
comparator: RuntimeConditionComparator::Ge,
value: 250000,
}]
);
}
#[test]
fn decodes_real_named_cargo_production_threshold_from_checked_in_metadata() {
let condition_row = build_real_condition_row_with_threshold(
REAL_CARGO_PRODUCTION_CONDITION_TEMPLATE_ID,
4,
125,
Some("Cargo Production Slot 1"),
);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Cargo Production: Cargo Production Slot 1")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0].recovered_cargo_slot,
Some(1)
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::CargoProductionSlotThreshold {
slot: 1,
label: "Cargo Production Slot 1".to_string(),
comparator: RuntimeConditionComparator::Eq,
value: 125,
}]
);
}
#[test]
fn decodes_real_world_scalar_thresholds_from_checked_in_metadata() {
let condition_rows = vec![
build_real_condition_row_with_threshold(
REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
0,
200,
None,
),
build_real_condition_row_with_threshold(
REAL_FACTORY_PRODUCTION_TOTAL_CONDITION_ID,
4,
125,
None,
),
build_real_condition_row_with_threshold(
REAL_FARM_MINE_PRODUCTION_TOTAL_CONDITION_ID,
4,
75,
None,
),
build_real_condition_row_with_threshold(
REAL_OTHER_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
4,
30,
None,
),
build_real_condition_row_with_threshold(
REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
4,
18,
None,
),
build_real_condition_row_with_threshold(
REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
4,
750000,
None,
),
];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&condition_rows,
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("Cargo Production Total")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_scalar_threshold")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![
RuntimeCondition::CargoProductionTotalThreshold {
comparator: RuntimeConditionComparator::Ge,
value: 200,
},
RuntimeCondition::FactoryProductionTotalThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 125,
},
RuntimeCondition::FarmMineProductionTotalThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 75,
},
RuntimeCondition::OtherCargoProductionTotalThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 30,
},
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 18,
},
RuntimeCondition::TerritoryAccessCostThreshold {
comparator: RuntimeConditionComparator::Eq,
value: 750000,
},
]
);
}
#[test]
fn decodes_real_world_flag_condition_from_checked_in_world_condition_metadata() {
let condition_row = build_real_condition_row_with_threshold(2535, 4, 1, None);
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[condition_row],
[&[], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.metric
.as_deref(),
Some("World Flag: Disable Stock Buying and Selling")
);
assert_eq!(
summary.records[0].standalone_condition_rows[0]
.semantic_family
.as_deref(),
Some("world_flag_equals")
);
assert_eq!(
summary.records[0].decoded_conditions,
vec![RuntimeCondition::WorldFlagEquals {
key: "world.disable_stock_buying_and_selling".to_string(),
value: true,
}]
);
}
#[test]
fn looks_up_checked_in_world_scalar_condition_metadata() {
let named_cargo =
real_ordinary_condition_metadata(REAL_CARGO_PRODUCTION_CONDITION_TEMPLATE_ID)
.expect("named cargo condition metadata should exist");
assert_eq!(named_cargo.label, "%1 Production");
let availability =
real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID)
.expect("availability condition metadata should exist");
assert_eq!(availability.label, "Unknown Loco Available");
let cost = real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID)
.expect("cost condition metadata should exist");
assert_eq!(cost.label, "Unknown Loco Cost");
let cargo = real_ordinary_condition_metadata(REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID)
.expect("cargo condition metadata should exist");
assert_eq!(cargo.label, "All Cargo Production");
let factory = real_ordinary_condition_metadata(REAL_FACTORY_PRODUCTION_TOTAL_CONDITION_ID)
.expect("factory production condition metadata should exist");
assert_eq!(factory.label, "All Factory Production");
let farm_mine =
real_ordinary_condition_metadata(REAL_FARM_MINE_PRODUCTION_TOTAL_CONDITION_ID)
.expect("farm/mine production condition metadata should exist");
assert_eq!(farm_mine.label, "All Farm/Mine Production");
let build_limit =
real_ordinary_condition_metadata(REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID)
.expect("build-limit condition metadata should exist");
assert_eq!(build_limit.label, "Limited Track Building Amount");
let access_cost = real_ordinary_condition_metadata(REAL_TERRITORY_ACCESS_COST_CONDITION_ID)
.expect("territory-access-cost condition metadata should exist");
assert_eq!(access_cost.label, "Access Rights Cost:");
}
#[test]
fn looks_up_checked_in_chairman_and_governance_condition_metadata() {
let world_variable = real_ordinary_condition_metadata(REAL_WORLD_VARIABLE_1_CONDITION_ID)
.expect("world-variable condition metadata should exist");
assert_eq!(world_variable.label, "Game Variable 1");
let player_variable = real_ordinary_condition_metadata(REAL_PLAYER_VARIABLE_3_CONDITION_ID)
.expect("player-variable condition metadata should exist");
assert_eq!(player_variable.label, "Player Variable 3");
let chairman_cash = real_ordinary_condition_metadata(REAL_CHAIRMAN_CASH_CONDITION_ID)
.expect("chairman cash condition metadata should exist");
assert_eq!(chairman_cash.label, "Player Cash");
let holdings = real_ordinary_condition_metadata(REAL_CHAIRMAN_HOLDINGS_TOTAL_CONDITION_ID)
.expect("chairman holdings condition metadata should exist");
assert_eq!(holdings.label, "Player Stock Value");
let net_worth = real_ordinary_condition_metadata(REAL_CHAIRMAN_NET_WORTH_CONDITION_ID)
.expect("chairman net worth condition metadata should exist");
assert_eq!(net_worth.label, "Player Net Worth");
let purchasing_power =
real_ordinary_condition_metadata(REAL_CHAIRMAN_PURCHASING_POWER_CONDITION_ID)
.expect("chairman purchasing-power condition metadata should exist");
assert_eq!(purchasing_power.label, "Purchasing Power");
let investor_confidence =
real_ordinary_condition_metadata(REAL_INVESTOR_CONFIDENCE_CONDITION_ID)
.expect("investor-confidence condition metadata should exist");
assert_eq!(investor_confidence.label, "Investor Confidence");
let credit_rating = real_ordinary_condition_metadata(REAL_CREDIT_RATING_CONDITION_ID)
.expect("credit-rating condition metadata should exist");
assert_eq!(credit_rating.label, "Credit Rating");
let prime_rate = real_ordinary_condition_metadata(REAL_PRIME_RATE_CONDITION_ID)
.expect("prime-rate condition metadata should exist");
assert_eq!(prime_rate.label, "Prime Rate");
let management_attitude =
real_ordinary_condition_metadata(REAL_MANAGEMENT_ATTITUDE_CONDITION_ID)
.expect("management-attitude condition metadata should exist");
assert_eq!(management_attitude.label, "Management Attitude");
let book_value = real_ordinary_condition_metadata(REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID)
.expect("book value condition metadata should exist");
assert_eq!(book_value.label, "Book Value Per Share");
}
#[test]
fn decodes_world_variable_condition() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_WORLD_VARIABLE_1_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&111_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Game Variable 1".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Game Variable 1 == 111".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::WorldVariableThreshold {
index: 1,
comparator: RuntimeConditionComparator::Eq,
value: 111,
})
);
}
#[test]
fn decodes_player_variable_condition_from_selected_player_scope() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_PLAYER_VARIABLE_3_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&333_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Player Variable 3".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Player Variable 3 == 333".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
let negative_scope = SmpLoadedPackedEventNegativeSentinelScopeSummary {
company_test_scope: RuntimeCompanyConditionTestScope::Disabled,
player_test_scope: RuntimePlayerConditionTestScope::SelectedPlayerOnly,
territory_scope_selector_is_0x63: false,
source_row_indexes: vec![0],
};
assert_eq!(
decode_real_condition_row(&row, Some(&negative_scope)),
Some(RuntimeCondition::PlayerVariableThreshold {
target: RuntimePlayerTarget::SelectedPlayer,
index: 3,
comparator: RuntimeConditionComparator::Eq,
value: 333,
})
);
}
#[test]
fn decodes_territory_variable_condition_with_world_territory_scope() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_TERRITORY_VARIABLE_4_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&444_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Territory Variable 4".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Territory Variable 4 == 444".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
let negative_scope = SmpLoadedPackedEventNegativeSentinelScopeSummary {
company_test_scope: RuntimeCompanyConditionTestScope::Disabled,
player_test_scope: RuntimePlayerConditionTestScope::Disabled,
territory_scope_selector_is_0x63: true,
source_row_indexes: vec![0],
};
assert_eq!(
decode_real_condition_row(&row, Some(&negative_scope)),
Some(RuntimeCondition::TerritoryVariableThreshold {
target: RuntimeTerritoryTarget::AllTerritories,
index: 4,
comparator: RuntimeConditionComparator::Eq,
value: 444,
})
);
}
#[test]
fn decodes_chairman_cash_condition_from_selected_player_scope() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_CHAIRMAN_CASH_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&500_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Player Cash".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Player Cash == 500".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
let negative_scope = SmpLoadedPackedEventNegativeSentinelScopeSummary {
company_test_scope: RuntimeCompanyConditionTestScope::Disabled,
player_test_scope: RuntimePlayerConditionTestScope::SelectedPlayerOnly,
territory_scope_selector_is_0x63: false,
source_row_indexes: vec![0],
};
assert_eq!(
decode_real_condition_row(&row, Some(&negative_scope)),
Some(RuntimeCondition::ChairmanNumericThreshold {
target: RuntimeChairmanTarget::SelectedChairman,
metric: RuntimeChairmanMetric::CurrentCash,
comparator: RuntimeConditionComparator::Eq,
value: 500,
})
);
}
#[test]
fn decodes_book_value_per_share_condition_to_company_metric() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_BOOK_VALUE_PER_SHARE_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&2620_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Book Value Per Share".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Book Value Per Share == 2620".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: RuntimeCompanyMetric::BookValuePerShare,
comparator: RuntimeConditionComparator::Eq,
value: 2620,
})
);
}
#[test]
fn decodes_investor_confidence_condition_to_company_metric() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_INVESTOR_CONFIDENCE_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&37_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Investor Confidence".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Investor Confidence == 37".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: RuntimeCompanyMetric::InvestorConfidence,
comparator: RuntimeConditionComparator::Eq,
value: 37,
})
);
}
#[test]
fn decodes_management_attitude_condition_to_company_metric() {
let row = SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: REAL_MANAGEMENT_ATTITUDE_CONDITION_ID,
subtype: 4,
flag_bytes: {
let mut bytes = vec![0; 25];
bytes[0..4].copy_from_slice(&58_i32.to_le_bytes());
bytes
},
candidate_name: None,
comparator: Some("eq".to_string()),
metric: Some("Management Attitude".to_string()),
semantic_family: Some("numeric_threshold".to_string()),
semantic_preview: Some("Test Management Attitude == 58".to_string()),
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
};
assert_eq!(
decode_real_condition_row(&row, None),
Some(RuntimeCondition::CompanyNumericThreshold {
target: RuntimeCompanyTarget::ConditionTrueCompany,
metric: RuntimeCompanyMetric::ManagementAttitude,
comparator: RuntimeConditionComparator::Eq,
value: 58,
})
);
}
#[test]
fn looks_up_checked_in_world_flag_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(110).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Disable Stock Buying and Selling");
assert_eq!(metadata.parameter_family, "world_flag_toggle");
assert_eq!(
metadata.runtime_key,
Some("world.disable_stock_buying_and_selling")
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_checked_in_credit_rating_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(56).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Credit Rating");
assert_eq!(metadata.target_mask_bits, 0x0b);
assert_eq!(metadata.parameter_family, "company_governance_scalar");
assert_eq!(
real_grouped_effect_runtime_status_name(metadata.runtime_status),
"executable"
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn checked_in_event_effect_table_covers_the_full_exported_descriptor_set() {
let rows = checked_in_event_effect_descriptor_rows();
assert_eq!(rows.len(), 520);
for descriptor_id in 0..520_u32 {
assert!(
real_grouped_effect_descriptor_metadata(descriptor_id).is_some(),
"descriptor {descriptor_id} should be recoverable from the checked-in effect table"
);
}
}
#[test]
fn looks_up_checked_in_prime_rate_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(57).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Prime Rate");
assert_eq!(metadata.target_mask_bits, 0x0b);
assert_eq!(metadata.parameter_family, "company_governance_scalar");
assert_eq!(
real_grouped_effect_runtime_status_name(metadata.runtime_status),
"executable"
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn classifies_shell_owned_finance_descriptors_from_checked_in_effect_table() {
let stock_prices =
real_grouped_effect_descriptor_metadata(55).expect("descriptor metadata should exist");
assert_eq!(stock_prices.label, "Stock Prices");
assert_eq!(
stock_prices.parameter_family,
"company_finance_shell_scalar"
);
assert_eq!(
real_grouped_effect_runtime_status_name(stock_prices.runtime_status),
"shell_owned"
);
assert!(!stock_prices.executable_in_runtime);
let merger_premium =
real_grouped_effect_descriptor_metadata(58).expect("descriptor metadata should exist");
assert_eq!(merger_premium.label, "Merger Premium");
assert_eq!(
merger_premium.parameter_family,
"company_finance_shell_scalar"
);
assert_eq!(
real_grouped_effect_runtime_status_name(merger_premium.runtime_status),
"shell_owned"
);
assert!(!merger_premium.executable_in_runtime);
}
#[test]
fn decodes_credit_rating_descriptor_into_company_governance_scalar_effect() {
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 56,
raw_scalar_value: 640,
opcode: 3,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let record_body = build_real_event_record(
[b"Gov", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [1, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&[row_bytes], &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Credit Rating")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.grouped_target_subject
.as_deref(),
Some("company")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetCompanyGovernanceScalar {
target: RuntimeCompanyTarget::SelectedCompany,
metric: RuntimeCompanyMetric::CreditRating,
value: 640,
}]
);
}
#[test]
fn looks_up_recovered_world_toggle_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(111).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Disable Margin Buying/Short Selling Stock");
assert_eq!(metadata.parameter_family, "world_flag_toggle");
assert_eq!(
runtime_world_flag_key(metadata),
Some("world.disable_margin_buying_short_selling_stock".to_string())
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_limited_track_building_amount_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(122).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Limited Track Building Amount");
assert_eq!(metadata.parameter_family, "world_track_build_limit_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_late_world_toggle_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(143).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Disable Train Crashes AND Breakdowns");
assert_eq!(metadata.parameter_family, "world_flag_toggle");
assert_eq!(
runtime_world_flag_key(metadata),
Some("world.disable_train_crashes_and_breakdowns".to_string())
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_locomotive_availability_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(250).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Big Boy 4-8-8-4 Availability");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_upper_band_recovered_locomotive_availability_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(457).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Upper-Band Locomotive Availability Slot 1");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
assert_eq!(recovered_locomotive_availability_loco_id(457), None);
}
#[test]
fn looks_up_extended_lower_band_locomotive_availability_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(301).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Zephyr Availability");
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
assert_eq!(recovered_locomotive_availability_loco_id(301), Some(61));
assert!(metadata.executable_in_runtime);
}
#[test]
fn parses_recovered_locomotive_availability_row_with_structured_locomotive_id() {
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 250,
raw_scalar_value: 1,
opcode: 3,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let row = parse_real_grouped_effect_row_summary(&row_bytes, 0, 0, None)
.expect("row should parse");
assert_eq!(row.descriptor_id, 250);
assert_eq!(
row.descriptor_label.as_deref(),
Some("Big Boy 4-8-8-4 Availability")
);
assert_eq!(row.recovered_locomotive_id, Some(10));
assert_eq!(
row.parameter_family.as_deref(),
Some("locomotive_availability_scalar")
);
}
#[test]
fn looks_up_recovered_cargo_production_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(230).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Cargo Production Slot 1");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_production_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_all_cargo_price_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(105).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "All Cargo Prices");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_price_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_named_cargo_price_slot_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(106).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Alcohol Price");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_price_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_runtime_variable_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(43).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Company Variable 1");
assert_eq!(metadata.target_mask_bits, 0x01);
assert_eq!(metadata.parameter_family, "runtime_variable_scalar");
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_aggregate_cargo_production_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(177).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "All Cargo Production");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_production_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_grounded_named_cargo_production_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(180).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Alcohol Production");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "cargo_production_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_lower_band_locomotive_cost_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(352).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "2-D-2 Cost");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
assert_eq!(metadata.runtime_key, None);
assert_eq!(recovered_locomotive_cost_loco_id(352), Some(1));
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_upper_band_locomotive_cost_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(475).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Upper-Band Locomotive Cost Slot 1");
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
assert_eq!(recovered_locomotive_cost_loco_id(475), None);
assert!(!metadata.executable_in_runtime);
}
#[test]
fn looks_up_extended_lower_band_locomotive_cost_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(412).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Zephyr Cost");
assert_eq!(metadata.parameter_family, "locomotive_cost_scalar");
assert_eq!(recovered_locomotive_cost_loco_id(412), Some(61));
assert!(metadata.executable_in_runtime);
}
#[test]
fn looks_up_recovered_territory_access_cost_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(453).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Territory Access Cost");
assert_eq!(metadata.target_mask_bits, 0x08);
assert_eq!(metadata.parameter_family, "territory_access_cost_scalar");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn parses_recovered_locomotive_cost_row_with_structured_locomotive_id() {
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 352,
raw_scalar_value: 250000,
opcode: 3,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let row = parse_real_grouped_effect_row_summary(&row_bytes, 0, 0, None)
.expect("row should parse");
assert_eq!(row.descriptor_id, 352);
assert_eq!(row.descriptor_label.as_deref(), Some("2-D-2 Cost"));
assert_eq!(row.recovered_locomotive_id, Some(1));
assert_eq!(
row.parameter_family.as_deref(),
Some("locomotive_cost_scalar")
);
}
#[test]
fn parses_grounded_named_cargo_production_row_with_label() {
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 180,
raw_scalar_value: 160,
opcode: 3,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let row = parse_real_grouped_effect_row_summary(&row_bytes, 0, 0, None)
.expect("row should parse");
assert_eq!(row.descriptor_id, 180);
assert_eq!(row.descriptor_label.as_deref(), Some("Alcohol Production"));
assert_eq!(row.recovered_cargo_label.as_deref(), Some("Alcohol"));
assert_eq!(
row.parameter_family.as_deref(),
Some("cargo_production_scalar")
);
}
#[test]
fn parses_grounded_named_cargo_price_row_with_label() {
let row_bytes = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 106,
raw_scalar_value: 140,
opcode: 3,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let row = parse_real_grouped_effect_row_summary(&row_bytes, 0, 0, None)
.expect("row should parse");
assert_eq!(row.descriptor_id, 106);
assert_eq!(row.descriptor_label.as_deref(), Some("Alcohol Price"));
assert_eq!(row.recovered_cargo_label.as_deref(), Some("Alcohol"));
assert_eq!(row.parameter_family.as_deref(), Some("cargo_price_scalar"));
}
#[test]
fn looks_up_recovered_locomotive_policy_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(454).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "All Steam Locos Avail.");
assert_eq!(metadata.parameter_family, "world_flag_toggle");
assert_eq!(
metadata.runtime_key,
Some("world.all_steam_locos_available")
);
assert!(metadata.executable_in_runtime);
}
#[test]
fn decodes_recovered_locomotive_policy_descriptor_from_checked_in_metadata() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 454,
opcode: 0,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"Locos", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 6,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("All Steam Locos Avail.")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_flag_toggle")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetWorldFlag {
key: "world.all_steam_locos_available".to_string(),
value: true,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn looks_up_checked_in_deactivate_player_descriptor_metadata() {
let metadata =
real_grouped_effect_descriptor_metadata(14).expect("descriptor metadata should exist");
assert_eq!(metadata.label, "Deactivate Player");
assert_eq!(metadata.parameter_family, "player_lifecycle_toggle");
assert_eq!(metadata.runtime_key, None);
assert!(metadata.executable_in_runtime);
}
#[test]
fn decodes_real_deactivate_player_descriptor_from_checked_in_metadata() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 14,
opcode: 1,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"Players", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [1, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Deactivate Player")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("player_lifecycle_toggle")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::DeactivatePlayer {
target: RuntimePlayerTarget::SelectedPlayer,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_real_world_flag_descriptor_with_checked_in_runtime_key() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 110,
opcode: 0,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Disable Stock Buying and Selling")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_flag_toggle")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetWorldFlag {
key: "world.disable_stock_buying_and_selling".to_string(),
value: true,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_recovered_world_toggle_descriptor_family() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 131,
opcode: 0,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Disable Starting Any Companies")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_flag_toggle")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetWorldFlag {
key: "world.disable_starting_any_companies".to_string(),
value: true,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_limited_track_building_amount_descriptor_family() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 122,
opcode: 3,
raw_scalar_value: 18,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 6,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("Limited Track Building Amount")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_track_build_limit_scalar")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetLimitedTrackBuildingAmount { value: 18 }]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_recovered_late_world_toggle_descriptor_family() {
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 144,
opcode: 0,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
});
let group0_rows = vec![grouped_row];
let record_body = build_real_event_record(
[b"World", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&group0_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.descriptor_label
.as_deref(),
Some("AI Ignore Territories At Startup")
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.parameter_family
.as_deref(),
Some("world_flag_toggle")
);
assert_eq!(
summary.records[0].decoded_actions,
vec![RuntimeEffect::SetWorldFlag {
key: "world.ai_ignore_territories_at_startup".to_string(),
value: true,
}]
);
assert!(summary.records[0].executable_import_ready);
}
#[test]
fn decodes_negative_sentinel_scope_modifiers_and_territory_marker() {
for (value, expected) in [
(0, RuntimeCompanyConditionTestScope::Disabled),
(1, RuntimeCompanyConditionTestScope::AllCompanies),
(2, RuntimeCompanyConditionTestScope::SelectedCompanyOnly),
(3, RuntimeCompanyConditionTestScope::AiCompaniesOnly),
(4, RuntimeCompanyConditionTestScope::HumanCompaniesOnly),
] {
assert_eq!(decode_company_condition_test_scope(value), Some(expected));
}
for (value, expected) in [
(0, RuntimePlayerConditionTestScope::Disabled),
(1, RuntimePlayerConditionTestScope::AllPlayers),
(2, RuntimePlayerConditionTestScope::SelectedPlayerOnly),
(3, RuntimePlayerConditionTestScope::AiPlayersOnly),
(4, RuntimePlayerConditionTestScope::HumanPlayersOnly),
] {
assert_eq!(decode_player_condition_test_scope(value), Some(expected));
}
let rows = vec![SmpLoadedPackedEventConditionRowSummary {
row_index: 0,
raw_condition_id: -1,
subtype: 4,
flag_bytes: vec![0x30; 25],
candidate_name: Some("AutoPlant".to_string()),
comparator: None,
metric: None,
semantic_family: None,
semantic_preview: None,
recovered_cargo_slot: None,
recovered_cargo_class: None,
requires_candidate_name_binding: false,
notes: vec![],
}];
let summary = derive_negative_sentinel_scope_summary(
&rows,
&SmpLoadedPackedEventCompactControlSummary {
mode_byte_0x7ef: 6,
primary_selector_0x7f0: 0x63,
grouped_mode_0x7f4: 2,
one_shot_header_0x7f5: 1,
modifier_flag_0x7f9: 4,
modifier_flag_0x7fa: 2,
grouped_target_scope_ordinals_0x7fb: vec![0, 1, 2, 3],
grouped_scope_checkboxes_0x7ff: vec![1, 0, 0, 0],
summary_toggle_0x800: 1,
grouped_territory_selectors_0x80f: vec![-1, -1, -1, -1],
},
)
.expect("negative sentinel summary should derive");
assert_eq!(
summary.company_test_scope,
RuntimeCompanyConditionTestScope::HumanCompaniesOnly
);
assert_eq!(
summary.player_test_scope,
RuntimePlayerConditionTestScope::SelectedPlayerOnly
);
assert!(summary.territory_scope_selector_is_0x63);
assert_eq!(summary.source_row_indexes, vec![0]);
}
#[test]
fn classifies_real_grouped_row_semantic_families() {
let grouped_rows = vec![
build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 2,
opcode: 1,
raw_scalar_value: 1,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
}),
build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 2,
opcode: 4,
raw_scalar_value: 25,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 2,
value_word_0x16: 6,
locomotive_name: None,
}),
build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 2,
opcode: 3,
raw_scalar_value: 250,
value_byte_0x09: 0,
value_dword_0x0d: 0,
value_byte_0x11: 0,
value_byte_0x12: 0,
value_word_0x14: 0,
value_word_0x16: 0,
locomotive_name: None,
}),
build_real_grouped_effect_row(RealGroupedEffectRowSpec {
descriptor_id: 2,
opcode: 8,
raw_scalar_value: 7,
value_byte_0x09: 1,
value_dword_0x0d: 12,
value_byte_0x11: 2,
value_byte_0x12: 3,
value_word_0x14: 24,
value_word_0x16: 36,
locomotive_name: Some("Mikado"),
}),
];
let record_body = build_real_event_record(
[b"Semantic", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 7,
primary_selector_0x7f0: 0x63,
grouped_mode_0x7f4: 1,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [1, 1, 1, 1],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 0,
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
}),
&[],
[&grouped_rows, &[], &[], &[]],
);
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
let families = summary.records[0]
.grouped_effect_rows
.iter()
.map(|row| row.semantic_family.as_deref().unwrap_or(""))
.collect::<Vec<_>>();
assert_eq!(
families,
vec![
"bool_toggle",
"timed_duration",
"scalar_assignment",
"multivalue_scalar",
]
);
assert_eq!(
summary.records[0].grouped_effect_rows[0]
.semantic_preview
.as_deref(),
Some("Set Company Cash to TRUE")
);
assert_eq!(
summary.records[0].grouped_effect_rows[1]
.semantic_preview
.as_deref(),
Some("Set Company Cash to 25 for 2 years 6 months")
);
assert_eq!(
summary.records[0].grouped_effect_rows[2]
.semantic_preview
.as_deref(),
Some("Set Company Cash to 250")
);
assert_eq!(
summary.records[0].grouped_effect_rows[3]
.semantic_preview
.as_deref(),
Some("Set Company Cash to 7 with aux [2, 3, 24, 36]")
);
}
#[test]
fn rejects_truncated_real_style_event_runtime_record() {
let mut record_body = build_real_event_record(
[b"Oops", b"", b"", b"", b"", b""],
Some(RealCompactControlSpec {
mode_byte_0x7ef: 5,
primary_selector_0x7f0: 0,
grouped_mode_0x7f4: 0,
one_shot_header_0x7f5: 0,
modifier_flag_0x7f9: 0,
modifier_flag_0x7fa: 0,
grouped_target_scope_ordinals_0x7fb: [0, 0, 0, 0],
grouped_scope_checkboxes_0x7ff: [0, 0, 0, 0],
summary_toggle_0x800: 0,
grouped_territory_selectors_0x80f: [0, 0, 0, 0],
}),
&[],
[&[], &[], &[], &[]],
);
record_body.pop();
let mut bytes = Vec::new();
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for word in header_words {
bytes.extend_from_slice(&word.to_le_bytes());
}
bytes.extend_from_slice(&[0x00, 0x00]);
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
bytes.extend_from_slice(&record_body);
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
let report = inspect_smp_bytes(&bytes);
let summary = report
.event_runtime_collection_summary
.as_ref()
.expect("event runtime collection summary should parse");
assert_eq!(summary.records[0].decode_status, "unsupported_framing");
assert_eq!(summary.records[0].payload_family, "unsupported_framing");
}
#[test]
fn loads_event_runtime_collection_summary_from_report() {
let mut report = inspect_smp_bytes(&[]);
let classic_probe = SmpClassicRehydrateProfileProbe {
profile_family: "rt3-classic-save-container-v1".to_string(),
progress_32dc_offset: 0x76e8,
progress_3714_offset: 0x76ec,
progress_3715_offset: 0x77f8,
packed_profile_offset: 0x76f0,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpClassicPackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 3,
map_path_offset: 0x13,
map_path: Some("British Isles.gmp".to_string()),
display_name_offset: 0x46,
display_name: Some("British Isles".to_string()),
profile_byte_0x77: 0,
profile_byte_0x77_hex: "0x00".to_string(),
profile_byte_0x82: 0,
profile_byte_0x82_hex: "0x00".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
};
report.classic_rehydrate_profile_probe = Some(classic_probe.clone());
report.save_load_summary = build_save_load_summary(
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-classic-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
None,
Some(&classic_probe),
None,
None,
);
report.event_runtime_collection_summary = Some(SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
mechanism_family: "classic-save-rehydrate-v1".to_string(),
mechanism_confidence: "grounded".to_string(),
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
metadata_tag_offset: 0x7100,
records_tag_offset: 0x7200,
close_tag_offset: 0x7600,
packed_state_version: 0x3e9,
packed_state_version_hex: "0x000003e9".to_string(),
live_id_bound: 5,
live_record_count: 3,
live_entry_ids: vec![1, 3, 5],
decoded_record_count: 0,
imported_runtime_record_count: 0,
records: build_unsupported_event_runtime_record_summaries(&[1, 3, 5], "test summary"),
});
let slice = load_save_slice_from_report(&report).expect("classic save slice");
assert_eq!(
slice
.event_runtime_collection
.as_ref()
.map(|summary| summary.live_entry_ids.clone()),
Some(vec![1, 3, 5])
);
}
#[test]
fn loads_rt3_105_save_slice_from_report() {
let mut report = inspect_smp_bytes(&[]);
let packed_profile = SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
packed_profile_offset: 0x73c0,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 2,
header_flag_word_3: 1,
header_flag_word_3_hex: "0x00000001".to_string(),
map_path_offset: 0x10,
map_path: Some("Alternate USA.gmp".to_string()),
display_name_offset: 0x43,
display_name: Some("Alternate USA".to_string()),
profile_byte_0x77: 0x07,
profile_byte_0x77_hex: "0x07".to_string(),
profile_byte_0x82: 0x4d,
profile_byte_0x82_hex: "0x4d".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
};
let name_table = SmpRt3105SaveNameTableProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-bridge-secondary-block".to_string(),
semantic_family: "scenario-named-candidate-availability-table".to_string(),
semantic_alignment: vec![],
header_offset: 0x6a70,
header_word_0: 0,
header_word_0_hex: "0x00000000".to_string(),
header_word_1: 0,
header_word_1_hex: "0x00000000".to_string(),
header_word_2: 0x332e,
header_word_2_hex: "0x0000332e".to_string(),
entry_stride: 0x22,
entry_stride_hex: "0x22".to_string(),
header_prefix_word_count: 11,
observed_entry_capacity: 0x44,
observed_entry_count: 2,
zero_trailer_entry_count: 1,
nonzero_trailer_entry_count: 1,
distinct_trailer_words: vec![0, 1],
distinct_trailer_hex_words: vec!["0x00000000".to_string(), "0x00000001".to_string()],
zero_trailer_entry_names: vec!["Uranium Mine".to_string()],
entries_offset: 0x6ad1,
entries_end_offset: 0x6b15,
trailing_footer_hex: "dc3200001437000000".to_string(),
footer_progress_word_0: 0x32dc,
footer_progress_word_0_hex: "0x000032dc".to_string(),
footer_progress_word_1: 0x3714,
footer_progress_word_1_hex: "0x00003714".to_string(),
footer_trailing_byte: 0,
footer_trailing_byte_hex: "0x00".to_string(),
footer_grounded_alignments: vec![],
entries: vec![
SmpRt3105SaveNameTableEntry {
index: 0,
offset: 0x6ad1,
text: "AutoPlant".to_string(),
availability_dword: 1,
availability_dword_hex: "0x00000001".to_string(),
trailer_word: 1,
trailer_word_hex: "0x00000001".to_string(),
},
SmpRt3105SaveNameTableEntry {
index: 1,
offset: 0x6af3,
text: "Uranium Mine".to_string(),
availability_dword: 0,
availability_dword_hex: "0x00000000".to_string(),
trailer_word: 0,
trailer_word_hex: "0x00000000".to_string(),
},
],
evidence: vec![],
};
let named_locomotive_table = SmpRt3105SaveNamedLocomotiveAvailabilityProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-locomotive-row-run".to_string(),
semantic_family: "scenario-named-locomotive-availability-table".to_string(),
semantic_alignment: vec![],
entries_offset: 0x7c78,
entry_stride: RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE,
entry_stride_hex: format!("0x{:x}", RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE),
observed_entry_count: 2,
zero_availability_count: 1,
zero_availability_names: vec!["Big Boy".to_string()],
entries_end_offset: 0x7c78 + 2 * RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE,
entries: vec![
SmpRt3105SaveNameTableEntry {
index: 0,
offset: 0x7c78,
text: "Big Boy".to_string(),
availability_dword: 0,
availability_dword_hex: "0x00000000".to_string(),
trailer_word: 0,
trailer_word_hex: "0x00000000".to_string(),
},
SmpRt3105SaveNameTableEntry {
index: 1,
offset: 0x7cb9,
text: "GP7".to_string(),
availability_dword: 1,
availability_dword_hex: "0x00000001".to_string(),
trailer_word: 1,
trailer_word_hex: "0x00000001".to_string(),
},
],
evidence: vec![],
};
let bridge = SmpRt3105PostSpanBridgeProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
bridge_family: "rt3-105-save-post-span-bridge-v1".to_string(),
bridge_evidence: vec![],
span_target_offset: 0x3678,
next_candidate_offset: Some(0x4f14),
next_candidate_delta_from_span_target: Some(0x189c),
packed_profile_offset: 0x73c0,
packed_profile_delta_from_span_target: 0x3d48,
next_candidate_delta_from_packed_profile: Some(-0x24ac),
selector_high_u16: 0x7110,
selector_high_hex: "0x7110".to_string(),
descriptor_high_u16: 0x7801,
descriptor_high_hex: "0x7801".to_string(),
next_candidate_high_u16_words: vec![0x6200, 0x0000, 0xfff7, 0x5515],
next_candidate_high_hex_words: vec![],
};
report.rt3_105_packed_profile_probe = Some(packed_profile.clone());
report.rt3_105_save_name_table_probe = Some(name_table.clone());
report.rt3_105_save_named_locomotive_availability_probe =
Some(named_locomotive_table.clone());
report.save_load_summary = build_save_load_summary(
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
Some(&bridge),
None,
Some(&packed_profile),
Some(&name_table),
);
let slice = load_save_slice_from_report(&report).expect("1.05 save slice");
assert_eq!(slice.mechanism_family, "rt3-105-save-post-span-bridge-v1");
assert_eq!(
slice
.profile
.as_ref()
.and_then(|profile| profile.map_path.as_deref()),
Some("Alternate USA.gmp")
);
assert_eq!(
slice
.candidate_availability_table
.as_ref()
.expect("candidate table")
.entries[1]
.text,
"Uranium Mine"
);
assert_eq!(
slice
.named_locomotive_availability_table
.as_ref()
.expect("named locomotive availability table")
.entries[1]
.text,
"GP7"
);
assert_eq!(
slice
.locomotive_catalog
.as_ref()
.expect("derived locomotive catalog")
.entries[0]
.name,
"Big Boy"
);
assert_eq!(
slice
.locomotive_catalog
.as_ref()
.expect("derived locomotive catalog")
.entries[1]
.locomotive_id,
2
);
}
#[test]
fn parses_save_world_selection_context_probe_from_fixed_world_block() {
let mut bytes = vec![0u8; 0x8000];
let chunk_tag_offset = 0x3ceusize;
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());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET
..payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET + 4]
.copy_from_slice(&7u32.to_le_bytes());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET
..payload_offset
+ RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET
+ 4]
.copy_from_slice(&9u32.to_le_bytes());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
..payload_offset
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT]
.copy_from_slice(&[3, 1, 4, 1, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET] = 1;
for (slot_index, role_gate) in [2u8, 1, 0, 2].into_iter().enumerate() {
bytes[payload_offset
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET
+ slot_index * RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE] = role_gate;
}
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
bytes[next_chunk_offset..next_chunk_offset + 4]
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
let probe = parse_save_world_selection_context_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("selection-context probe should parse");
assert_eq!(probe.chunk_tag_offset, chunk_tag_offset);
assert_eq!(probe.payload_offset, payload_offset);
assert_eq!(probe.selected_company_id, 7);
assert_eq!(probe.selected_chairman_profile_id, 9);
assert_eq!(probe.chairman_slot_selectors[..6], [3, 1, 4, 1, 5, 9]);
assert_eq!(probe.campaign_override_flag, 1);
assert_eq!(probe.chairman_role_gate_bytes[..4], [2, 1, 0, 2]);
}
#[test]
fn parses_save_world_economic_tuning_probe_from_fixed_world_block() {
let mut bytes = vec![0u8; 0x8000];
let chunk_tag_offset = 0x3ceusize;
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());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_MIRROR_RELATIVE_OFFSET
..payload_offset + RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_MIRROR_RELATIVE_OFFSET + 4]
.copy_from_slice(&1.5f32.to_bits().to_le_bytes());
for (lane_index, relative_offset) in
RT3_SAVE_WORLD_BLOCK_ECONOMIC_TUNING_PRIMARY_RELATIVE_OFFSETS
.iter()
.copied()
.enumerate()
{
let value = (lane_index as f32) + 10.25f32;
bytes[payload_offset + relative_offset..payload_offset + relative_offset + 4]
.copy_from_slice(&value.to_bits().to_le_bytes());
}
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
bytes[next_chunk_offset..next_chunk_offset + 4]
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
let probe = parse_save_world_economic_tuning_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("world economic tuning probe should parse");
assert_eq!(probe.chunk_tag_offset, chunk_tag_offset);
assert_eq!(probe.payload_offset, payload_offset);
assert_eq!(probe.mirror_lane.relative_offset_hex, "0xbda");
assert_eq!(probe.mirror_lane.value_f32, 1.5);
assert_eq!(probe.tuning_lanes.len(), 6);
assert_eq!(probe.tuning_lanes[0].relative_offset_hex, "0xbde");
assert_eq!(probe.tuning_lanes[0].value_f32, 10.25);
assert_eq!(probe.tuning_lanes[5].relative_offset_hex, "0xbf2");
assert_eq!(probe.tuning_lanes[5].value_f32, 15.25);
}
#[test]
fn parses_save_world_issue_37_probe_from_fixed_world_block() {
let mut bytes = vec![0u8; 0x8000];
let chunk_tag_offset = 0x3ceusize;
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());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET
..payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET + 4]
.copy_from_slice(&3u32.to_le_bytes());
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET
..payload_offset + RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET + 4]
.copy_from_slice(&0.06f32.to_bits().to_le_bytes());
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
bytes[next_chunk_offset..next_chunk_offset + 4]
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
let probe = parse_save_world_issue_37_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("world issue-0x37 probe should parse");
assert_eq!(probe.chunk_tag_offset, chunk_tag_offset);
assert_eq!(probe.payload_offset, payload_offset);
assert_eq!(probe.issue_value_lane.relative_offset_hex, "0x29");
assert_eq!(probe.issue_value_lane.value_i32, 3);
assert_eq!(probe.issue_37_raw_u8, 3);
assert_eq!(probe.issue_37_raw_hex, "0x03");
assert_eq!(probe.issue_38_raw_u8, 0);
assert_eq!(probe.issue_38_raw_hex, "0x00");
assert_eq!(probe.issue_39_raw_u8, 0);
assert_eq!(probe.issue_39_raw_hex, "0x00");
assert_eq!(probe.issue_3a_raw_u8, 0);
assert_eq!(probe.issue_3a_raw_hex, "0x00");
assert_eq!(probe.multiplier_lane.relative_offset_hex, "0x25");
assert!((probe.multiplier_lane.value_f32 - 0.06).abs() < f32::EPSILON);
}
#[test]
fn parses_save_world_finance_neighborhood_probe_from_fixed_world_block() {
let mut bytes = vec![0u8; 0x8000];
let chunk_tag_offset = 0x3ceusize;
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 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());
}
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_STOCK_POLICY_RELATIVE_OFFSET] = 1;
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_BOND_POLICY_RELATIVE_OFFSET] = 2;
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_BANKRUPTCY_POLICY_RELATIVE_OFFSET] = 3;
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_DIVIDEND_POLICY_RELATIVE_OFFSET] = 4;
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_BUILDING_DENSITY_GROWTH_RELATIVE_OFFSET
..payload_offset + RT3_SAVE_WORLD_BLOCK_BUILDING_DENSITY_GROWTH_RELATIVE_OFFSET + 4]
.copy_from_slice(&2u32.to_le_bytes());
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
bytes[next_chunk_offset..next_chunk_offset + 4]
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
let probe = parse_save_world_finance_neighborhood_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("world finance neighborhood probe should parse");
assert_eq!(probe.chunk_tag_offset, chunk_tag_offset);
assert_eq!(probe.payload_offset, payload_offset);
assert_eq!(
probe.dword_candidates.len(),
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.stock_policy_raw_u8, 1);
assert_eq!(probe.stock_policy_raw_hex, "0x01");
assert_eq!(probe.bond_policy_raw_u8, 2);
assert_eq!(probe.bond_policy_raw_hex, "0x02");
assert_eq!(probe.bankruptcy_policy_raw_u8, 3);
assert_eq!(probe.bankruptcy_policy_raw_hex, "0x03");
assert_eq!(probe.dividend_policy_raw_u8, 4);
assert_eq!(probe.dividend_policy_raw_hex, "0x04");
assert_eq!(probe.building_density_growth_setting_lane.raw_u32, 2);
assert_eq!(
probe
.building_density_growth_setting_lane
.relative_offset_hex,
"0x4c78"
);
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[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[16].label,
"finance_neighborhood_word_17"
);
assert_eq!(probe.dword_candidates[16].relative_offset_hex, "0x4d");
assert_eq!(probe.dword_candidates[16].value_i32, 17);
}
#[test]
fn loads_selection_only_company_and_chairman_context_from_save_world_probe() {
let mut report = inspect_smp_bytes(&[]);
report.save_load_summary = Some(SmpSaveLoadSummary {
file_extension_hint: Some("gms".to_string()),
container_profile_family: Some("rt3-105-save-container-v1".to_string()),
mechanism_family: "rt3-105-save-post-span-bridge-v1".to_string(),
mechanism_confidence: "mixed".to_string(),
packed_profile_kind: None,
packed_profile_family: None,
packed_profile_offset: None,
packed_profile_len: None,
map_path: None,
display_name: None,
profile_byte_0x77: None,
profile_byte_0x77_hex: None,
profile_byte_0x82: None,
profile_byte_0x82_hex: None,
profile_byte_0x97: None,
profile_byte_0x97_hex: None,
profile_byte_0xc5: None,
profile_byte_0xc5_hex: None,
trailer_family: Some("rt3-105-save-trailer-v1".to_string()),
bridge_family: Some("rt3-105-save-post-span-bridge-v1".to_string()),
candidate_table: None,
notes: vec![],
});
report.save_world_selection_context_probe = Some(SmpSaveWorldSelectionContextProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-selected-company-and-chairman-context".to_string(),
chunk_tag_offset: 0x3ce,
payload_offset: 0x3d2,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
selected_company_id_offset: 0x3ef,
selected_company_id: 1,
selected_company_id_hex: "0x00000001".to_string(),
selected_chairman_profile_id_offset: 0x3f3,
selected_chairman_profile_id: 9,
selected_chairman_profile_id_hex: "0x00000009".to_string(),
chairman_slot_selector_offset: 0x455,
chairman_slot_selectors: vec![3, 1, 4, 1, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
campaign_override_flag_offset: 0x493,
campaign_override_flag: 1,
campaign_override_flag_hex: "0x01".to_string(),
chairman_role_gate_offset: 0xf91,
chairman_role_gate_bytes: vec![2, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
evidence: vec![],
});
report.save_world_issue_37_probe = Some(SmpSaveWorldIssue37Probe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-save-world-issue-0x37".to_string(),
chunk_tag_offset: 0x3ce,
payload_offset: 0x3d2,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
issue_37_raw_u8: 3,
issue_37_raw_hex: "0x03".to_string(),
issue_38_raw_u8: 1,
issue_38_raw_hex: "0x01".to_string(),
issue_39_raw_u8: 2,
issue_39_raw_hex: "0x02".to_string(),
issue_3a_raw_u8: 4,
issue_3a_raw_hex: "0x04".to_string(),
issue_value_lane: SmpSaveDwordCandidate {
label: "issue_0x37_value".to_string(),
relative_offset: 0x29,
relative_offset_hex: "0x29".to_string(),
raw_u32: 3,
raw_u32_hex: "0x00000003".to_string(),
value_i32: 3,
value_f32: f32::from_bits(3),
},
multiplier_lane: SmpSaveDwordCandidate {
label: "issue_0x37_multiplier".to_string(),
relative_offset: 0x25,
relative_offset_hex: "0x25".to_string(),
raw_u32: 0x3d75c28f,
raw_u32_hex: "0x3d75c28f".to_string(),
value_i32: 1031127695,
value_f32: 0.06,
},
issue_opinion_base_terms_raw_i32: Vec::new(),
evidence: vec![],
});
report.save_world_economic_tuning_probe = Some(SmpSaveWorldEconomicTuningProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-save-world-economic-tuning".to_string(),
chunk_tag_offset: 0x3ce,
payload_offset: 0x3d2,
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
mirror_lane: SmpSaveDwordCandidate {
label: "economic_tuning_mirror_lane_0".to_string(),
relative_offset: 0xbda,
relative_offset_hex: "0xbda".to_string(),
raw_u32: 0x3f46d093,
raw_u32_hex: "0x3f46d093".to_string(),
value_i32: 1061605523,
value_f32: 0.7766201,
},
tuning_lanes: vec![
SmpSaveDwordCandidate {
label: "economic_tuning_lane_0".to_string(),
relative_offset: 0xbde,
relative_offset_hex: "0xbde".to_string(),
raw_u32: 0x3f400000,
raw_u32_hex: "0x3f400000".to_string(),
value_i32: 1061158912,
value_f32: 0.75,
},
SmpSaveDwordCandidate {
label: "economic_tuning_lane_1".to_string(),
relative_offset: 0xbe2,
relative_offset_hex: "0xbe2".to_string(),
raw_u32: 0x3be56042,
raw_u32_hex: "0x3be56042".to_string(),
value_i32: 1004888130,
value_f32: 0.007,
},
],
evidence: vec![],
});
report.save_company_collection_header_probe = Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-company-tagged-header-counts".to_string(),
semantic_family: "scenario-save-company-header-counts".to_string(),
metadata_tag_offset: 0x1000,
records_tag_offset: 0x1100,
close_tag_offset: 0x1200,
direct_collection_flag: 1,
direct_collection_flag_hex: "0x00000001".to_string(),
direct_record_stride: 0x7684,
direct_record_stride_hex: "0x00007684".to_string(),
live_id_bound: 5,
live_id_bound_hex: "0x00000005".to_string(),
live_record_count: 1,
live_record_count_hex: "0x00000001".to_string(),
header_words: vec![1, 0x7684, 5, 5, 5, 1],
header_hex_words: vec![
"0x00000001".to_string(),
"0x00007684".to_string(),
"0x00000005".to_string(),
"0x00000005".to_string(),
"0x00000005".to_string(),
"0x00000001".to_string(),
],
evidence: vec![],
});
report.save_chairman_profile_collection_header_probe =
Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-chairman-profile-tagged-header-counts".to_string(),
semantic_family: "scenario-save-chairman-profile-header-counts".to_string(),
metadata_tag_offset: 0x2000,
records_tag_offset: 0x2100,
close_tag_offset: 0x2200,
direct_collection_flag: 1,
direct_collection_flag_hex: "0x00000001".to_string(),
direct_record_stride: 0xcab,
direct_record_stride_hex: "0x00000cab".to_string(),
live_id_bound: 8,
live_id_bound_hex: "0x00000008".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![1, 0xcab, 8, 6, 8, 2],
header_hex_words: vec![
"0x00000001".to_string(),
"0x00000cab".to_string(),
"0x00000008".to_string(),
"0x00000006".to_string(),
"0x00000008".to_string(),
"0x00000002".to_string(),
],
evidence: vec![],
});
report.save_train_collection_header_probe = Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-train-tagged-header-counts".to_string(),
semantic_family: "scenario-save-train-header-counts".to_string(),
metadata_tag_offset: 0x3000,
records_tag_offset: 0x3100,
close_tag_offset: 0x3200,
direct_collection_flag: 1,
direct_collection_flag_hex: "0x00000001".to_string(),
direct_record_stride: 0x1d5,
direct_record_stride_hex: "0x000001d5".to_string(),
live_id_bound: 0x32,
live_id_bound_hex: "0x00000032".to_string(),
live_record_count: 0x14,
live_record_count_hex: "0x00000014".to_string(),
header_words: vec![1, 0x1d5, 0x32, 0x14, 0x32, 0x14],
header_hex_words: vec![
"0x00000001".to_string(),
"0x000001d5".to_string(),
"0x00000032".to_string(),
"0x00000014".to_string(),
"0x00000032".to_string(),
"0x00000014".to_string(),
],
evidence: vec![],
});
report.save_train_collection_directory_probe = Some(SmpSaveTrainCollectionDirectoryProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-train-live-directory".to_string(),
semantic_family: "scenario-save-train-live-directory".to_string(),
metadata_tag_offset: 0x3000,
records_tag_offset: 0x3100,
close_tag_offset: 0x3200,
directory_root_dword_index: 16,
directory_entry_dword_count: 3,
live_record_count: 0x14,
live_id_bound: 0x32,
chain_head_live_entry_id: Some(1),
chain_tail_live_entry_id: Some(20),
entries: vec![
SmpSaveTrainCollectionDirectoryEntryProbe {
live_entry_id: 1,
payload_relative_offset: 0x2af8,
payload_relative_offset_hex: "0x00002af8".to_string(),
payload_absolute_offset: 0x5afc,
previous_live_entry_id: 0,
previous_live_entry_id_hex: "0x00000000".to_string(),
next_live_entry_id: 2,
next_live_entry_id_hex: "0x00000002".to_string(),
},
SmpSaveTrainCollectionDirectoryEntryProbe {
live_entry_id: 2,
payload_relative_offset: 0x2ee0,
payload_relative_offset_hex: "0x00002ee0".to_string(),
payload_absolute_offset: 0x5ee4,
previous_live_entry_id: 1,
previous_live_entry_id_hex: "0x00000001".to_string(),
next_live_entry_id: 0,
next_live_entry_id_hex: "0x00000000".to_string(),
},
],
evidence: vec![],
});
report.save_region_collection_header_probe = Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-region-tagged-header-counts".to_string(),
semantic_family: "scenario-save-region-header-counts".to_string(),
metadata_tag_offset: 0x5000,
records_tag_offset: 0x5100,
close_tag_offset: 0x5200,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x96,
live_id_bound_hex: "0x00000096".to_string(),
live_record_count: 0x91,
live_record_count_hex: "0x00000091".to_string(),
header_words: vec![0, 6, 0x0a, 0x14, 0x96, 0x91],
header_hex_words: vec![
"0x00000000".to_string(),
"0x00000006".to_string(),
"0x0000000a".to_string(),
"0x00000014".to_string(),
"0x00000096".to_string(),
"0x00000091".to_string(),
],
evidence: vec![],
});
report.save_region_record_triplet_probe = Some(SmpSaveRegionRecordTripletProbe {
profile_family: "rt3-105-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: 0x5100,
close_tag_offset: 0x5200,
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: 0x6e,
policy_tag_relative_offset: 0x7e,
profile_tag_relative_offset: 0x9c,
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: 0x20,
policy_leading_f32_0: 552.0,
policy_leading_f32_1: 0.0,
policy_leading_f32_2: 276.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: 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_collection_header_probe =
Some(SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-tagged-header-counts".to_string(),
semantic_family: "scenario-save-placed-structure-header-counts".to_string(),
metadata_tag_offset: 0x4000,
records_tag_offset: 0x4100,
close_tag_offset: 0x4200,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x7ee,
live_id_bound_hex: "0x000007ee".to_string(),
live_record_count: 0x7ea,
live_record_count_hex: "0x000007ea".to_string(),
header_words: vec![0, 6, 0x0a, 0x14, 0x7ee, 0x7ea],
header_hex_words: vec![
"0x00000000".to_string(),
"0x00000006".to_string(),
"0x0000000a".to_string(),
"0x00000014".to_string(),
"0x000007ee".to_string(),
"0x000007ea".to_string(),
],
evidence: vec![],
});
let slice = load_save_slice_from_report(&report).expect("save slice");
let company_roster = slice.company_roster.expect("selection-only company roster");
assert_eq!(company_roster.observed_entry_count, 1);
assert_eq!(company_roster.selected_company_id, Some(1));
assert!(company_roster.entries.is_empty());
let chairman_table = slice
.chairman_profile_table
.expect("selection-only chairman table");
assert_eq!(chairman_table.observed_entry_count, 2);
assert_eq!(chairman_table.selected_chairman_profile_id, Some(9));
assert!(chairman_table.entries.is_empty());
let issue_37_state = slice
.world_issue_37_state
.expect("world issue-0x37 state should load");
assert_eq!(issue_37_state.issue_value, 3);
assert_eq!(issue_37_state.issue_38_value, 1);
assert_eq!(issue_37_state.issue_39_value, 2);
assert_eq!(issue_37_state.issue_3a_value, 4);
assert_eq!(issue_37_state.multiplier_raw_hex, "0x3d75c28f");
assert_eq!(issue_37_state.multiplier_value_f32_text, "0.060000");
let tuning_state = slice
.world_economic_tuning_state
.expect("world economic tuning state should load");
assert_eq!(tuning_state.mirror_raw_hex, "0x3f46d093");
assert_eq!(tuning_state.mirror_value_f32_text, "0.776620");
assert_eq!(
tuning_state.lane_value_f32_text,
vec!["0.750000", "0.007000"]
);
assert!(
slice
.notes
.iter()
.any(|note| note.contains("selected_company_id=1"))
);
assert!(
slice
.notes
.iter()
.any(|note| note.contains("selected_chairman_profile_id=9"))
);
assert!(
slice
.notes
.iter()
.any(|note| note.contains("grounded issue-0x37 pair: value=3"))
);
assert!(
slice
.notes
.iter()
.any(|note| note.contains("campaign_override_flag=1"))
);
assert!(
slice
.notes
.iter()
.any(|note| note.contains("tagged company header reports live_record_count=1"))
);
assert!(slice.notes.iter().any(|note| {
note.contains("tagged chairman/profile header reports live_record_count=2")
}));
assert!(
slice
.notes
.iter()
.any(|note| note.contains("tagged train header reports live_record_count=20"))
);
assert!(slice.notes.iter().any(|note| {
note.contains("tagged train metadata also exposes a live-entry directory")
}));
assert!(
slice.notes.iter().any(|note| {
note.contains("tagged region header reports live_record_count=145")
})
);
assert!(slice.notes.iter().any(|note| {
note.contains(
"tagged region records also expose 2 repeated 0x55f1/0x55f2/0x55f3 triplets",
)
}));
assert!(slice.notes.iter().any(|note| {
note.contains("tagged placed-structure header reports live_record_count=2026")
}));
}
#[test]
fn parses_company_tagged_collection_header_probe_from_exact_u32_tags() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x180usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000061a9u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000061aau32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000061abu32.to_le_bytes());
let header_words = [
1u32, 0x7684, 5, 5, 5, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let probe = parse_save_company_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("company header probe should parse");
assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
assert_eq!(probe.records_tag_offset, records_tag_offset);
assert_eq!(probe.close_tag_offset, close_tag_offset);
assert_eq!(probe.direct_record_stride, 0x7684);
assert_eq!(probe.live_id_bound, 5);
assert_eq!(probe.live_record_count, 1);
}
#[test]
fn parses_chairman_profile_tagged_collection_header_probe_from_exact_u32_tags() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x180usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let header_words = [
1u32, 0xcab, 8, 6, 8, 2, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let probe = parse_save_chairman_profile_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("chairman profile header probe should parse");
assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
assert_eq!(probe.records_tag_offset, records_tag_offset);
assert_eq!(probe.close_tag_offset, close_tag_offset);
assert_eq!(probe.direct_record_stride, 0xcab);
assert_eq!(probe.live_id_bound, 8);
assert_eq!(probe.live_record_count, 2);
}
#[test]
fn parses_train_tagged_collection_header_probe_from_exact_u32_tags() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x180usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let header_words = [
1u32, 0x1d5, 0x32, 0x14, 0x32, 0x14, 0x14, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let probe = parse_save_train_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("train header probe should parse");
assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
assert_eq!(probe.records_tag_offset, records_tag_offset);
assert_eq!(probe.close_tag_offset, close_tag_offset);
assert_eq!(probe.direct_collection_flag, 1);
assert_eq!(probe.direct_record_stride, 0x1d5);
assert_eq!(probe.live_id_bound, 0x32);
assert_eq!(probe.live_record_count, 0x14);
}
#[test]
fn parses_region_tagged_collection_header_probe_from_marker09_family() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x180usize;
let close_tag_offset = 0x1c0usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let header_words = [
0u32, 0x06, 0x0a, 0x14, 0x96, 0x91, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let marker_offset = records_tag_offset + 4 + 0x20;
bytes[marker_offset..marker_offset + 8].copy_from_slice(b"Marker09");
let probe = parse_save_region_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("region header probe should parse");
assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
assert_eq!(probe.records_tag_offset, records_tag_offset);
assert_eq!(probe.close_tag_offset, close_tag_offset);
assert_eq!(probe.direct_collection_flag, 0);
assert_eq!(probe.direct_record_stride, 0x06);
assert_eq!(probe.live_id_bound, 0x96);
assert_eq!(probe.live_record_count, 0x91);
}
#[test]
fn parses_train_collection_directory_probe_from_tagged_metadata_triplets() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x180usize;
let close_tag_offset = 0x1c0usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let header_words = [
1u32, 0x1d5, 0x32, 0x03, 0x32, 0x03, 0x14, 1, 0, 0, 1, 1, 0x14, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let triplets = [(0x2af8u32, 0u32, 2u32), (0x2ee0, 1, 3), (0x32c8, 2, 0)];
for (index, (offset_word, prev, next)) in triplets.into_iter().enumerate() {
let base = metadata_tag_offset
+ 4
+ (SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX + index * 3) * 4;
bytes[base..base + 4].copy_from_slice(&offset_word.to_le_bytes());
bytes[base + 4..base + 8].copy_from_slice(&prev.to_le_bytes());
bytes[base + 8..base + 12].copy_from_slice(&next.to_le_bytes());
}
let header_probe = parse_save_train_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("train header probe should parse");
let directory_probe =
parse_save_train_collection_directory_probe(&bytes, Some(&header_probe))
.expect("train directory probe should parse");
assert_eq!(directory_probe.directory_root_dword_index, 16);
assert_eq!(directory_probe.live_record_count, 3);
assert_eq!(directory_probe.chain_head_live_entry_id, Some(1));
assert_eq!(directory_probe.chain_tail_live_entry_id, Some(3));
assert_eq!(directory_probe.entries.len(), 3);
assert_eq!(directory_probe.entries[0].live_entry_id, 1);
assert_eq!(directory_probe.entries[0].payload_relative_offset, 0x2af8);
assert_eq!(directory_probe.entries[0].previous_live_entry_id, 0);
assert_eq!(directory_probe.entries[0].next_live_entry_id, 2);
assert_eq!(directory_probe.entries[2].live_entry_id, 3);
assert_eq!(directory_probe.entries[2].previous_live_entry_id, 2);
assert_eq!(directory_probe.entries[2].next_live_entry_id, 0);
}
#[test]
fn parses_region_record_triplet_probe_from_marker09_records() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x260usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let mut cursor = records_tag_offset + 4;
for (name, x, density, y) in [
("Marker09", 368.0f32, 0.0f32, 92.0f32),
("Marker10", 552.0f32, 1.5f32, 276.0f32),
] {
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
bytes[cursor + 4] = name.len() as u8;
bytes[cursor + 5..cursor + 5 + name.len()].copy_from_slice(name.as_bytes());
cursor += 0x10;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&x.to_bits().to_le_bytes());
bytes[cursor + 8..cursor + 12].copy_from_slice(&density.to_bits().to_le_bytes());
bytes[cursor + 12..cursor + 16].copy_from_slice(&y.to_bits().to_le_bytes());
bytes[cursor + 28..cursor + 30].copy_from_slice(&1u16.to_le_bytes());
cursor += 0x1e;
bytes[cursor..cursor + 2]
.copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
cursor += 0x40;
}
let header_probe = SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-region-tagged-header-counts".to_string(),
semantic_family: "scenario-save-region-header-counts".to_string(),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x96,
live_id_bound_hex: "0x00000096".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![0, 6, 0x0a, 0x14, 0x96, 0x02],
header_hex_words: vec![],
evidence: vec![],
};
let triplet_probe = parse_save_region_record_triplet_probe(&bytes, Some(&header_probe))
.expect("region triplet probe should parse");
assert_eq!(triplet_probe.record_count, 2);
assert_eq!(triplet_probe.entries[0].name, "Marker09");
assert_eq!(triplet_probe.entries[0].policy_tag_relative_offset, 0x10);
assert_eq!(triplet_probe.entries[0].profile_tag_relative_offset, 0x2e);
assert_eq!(triplet_probe.entries[0].policy_leading_f32_0, 368.0);
assert_eq!(triplet_probe.entries[0].policy_leading_f32_1, 0.0);
assert_eq!(triplet_probe.entries[0].policy_leading_f32_2, 92.0);
assert!(
triplet_probe.entries[0]
.pre_name_prefix_dword_candidates
.is_empty()
);
assert_eq!(
triplet_probe.entries[0].policy_reserved_dwords,
vec![0, 0, 0]
);
assert_eq!(
triplet_probe.entries[0]
.policy_reserved_dword_candidates
.len(),
3
);
assert_eq!(
triplet_probe.entries[0].policy_reserved_dword_candidates[0].relative_offset_hex,
"0x20"
);
assert_eq!(triplet_probe.entries[0].policy_trailing_word, 1);
assert_eq!(triplet_probe.entries[1].name, "Marker10");
assert_eq!(triplet_probe.entries[1].policy_leading_f32_0, 552.0);
assert_eq!(triplet_probe.entries[1].policy_leading_f32_1, 1.5);
assert_eq!(triplet_probe.entries[1].policy_leading_f32_2, 276.0);
assert!(
triplet_probe.entries[1]
.pre_name_prefix_dword_candidates
.is_empty()
);
assert_eq!(
triplet_probe.entries[1]
.policy_reserved_dword_candidates
.len(),
3
);
}
#[test]
fn parses_region_record_triplet_prefix_dword_candidates() {
let mut bytes = vec![0u8; 0x320];
let metadata_tag_offset = 0x0usize;
let records_tag_offset = 0x100usize;
let close_tag_offset = 0x200usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
let mut cursor = records_tag_offset + 4;
let first_record_relative_offset = 0usize;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
bytes[cursor + 4] = 8;
bytes[cursor + 5..cursor + 13].copy_from_slice(b"Marker11");
cursor += 0x10;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&100.0f32.to_bits().to_le_bytes());
bytes[cursor + 8..cursor + 12].copy_from_slice(&2.0f32.to_bits().to_le_bytes());
bytes[cursor + 12..cursor + 16].copy_from_slice(&50.0f32.to_bits().to_le_bytes());
bytes[cursor + 28..cursor + 30].copy_from_slice(&1u16.to_le_bytes());
cursor += 0x1e;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
cursor += 0x20;
let second_record_relative_offset = cursor - (records_tag_offset + 4);
bytes[cursor..cursor + 4].copy_from_slice(&0x11223344u32.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&0x55667788u32.to_le_bytes());
cursor += 8;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
bytes[cursor + 4] = 8;
bytes[cursor + 5..cursor + 13].copy_from_slice(b"Marker12");
cursor += 0x10;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&120.0f32.to_bits().to_le_bytes());
bytes[cursor + 8..cursor + 12].copy_from_slice(&3.0f32.to_bits().to_le_bytes());
bytes[cursor + 12..cursor + 16].copy_from_slice(&60.0f32.to_bits().to_le_bytes());
bytes[cursor + 16..cursor + 20].copy_from_slice(&0x01020304u32.to_le_bytes());
bytes[cursor + 20..cursor + 24].copy_from_slice(&0u32.to_le_bytes());
bytes[cursor + 24..cursor + 28].copy_from_slice(&0x05060708u32.to_le_bytes());
bytes[cursor + 28..cursor + 30].copy_from_slice(&1u16.to_le_bytes());
cursor += 0x1e;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
let directory_root_byte_offset = SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX * 4;
let first_payload_relative_offset = records_tag_offset - metadata_tag_offset;
let second_payload_relative_offset =
first_payload_relative_offset + second_record_relative_offset;
bytes[metadata_tag_offset + 4 + directory_root_byte_offset
..metadata_tag_offset + 8 + directory_root_byte_offset]
.copy_from_slice(&(first_payload_relative_offset as u32).to_le_bytes());
bytes[metadata_tag_offset + 16 + directory_root_byte_offset
..metadata_tag_offset + 20 + directory_root_byte_offset]
.copy_from_slice(&(second_payload_relative_offset as u32).to_le_bytes());
let header_probe = SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-region-tagged-header-counts".to_string(),
semantic_family: "scenario-save-region-header-counts".to_string(),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x96,
live_id_bound_hex: "0x00000096".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![0, 6, 0x0a, 0x14, 0x96, 0x02],
header_hex_words: vec![],
evidence: vec![],
};
let triplet_probe = parse_save_region_record_triplet_probe(&bytes, Some(&header_probe))
.expect("region triplet probe should parse");
assert_eq!(triplet_probe.entries.len(), 2);
assert_eq!(
triplet_probe.entries[0].record_payload_relative_offset,
first_record_relative_offset
);
assert_eq!(triplet_probe.entries[0].pre_name_prefix_len, 0);
assert_eq!(
triplet_probe.entries[1].record_payload_relative_offset,
second_record_relative_offset
);
assert_eq!(triplet_probe.entries[1].pre_name_prefix_len, 8);
assert_eq!(
triplet_probe.entries[1]
.pre_name_prefix_dword_candidates
.len(),
2
);
assert_eq!(
triplet_probe.entries[1].pre_name_prefix_dword_candidates[0].raw_u32_hex,
"0x11223344"
);
assert_eq!(
triplet_probe.entries[1].pre_name_prefix_dword_candidates[1].relative_offset_hex,
"0x52"
);
assert_eq!(
triplet_probe.entries[1].policy_reserved_dword_candidates[2].relative_offset_hex,
"0xcc"
);
assert_eq!(
triplet_probe.entries[1].policy_reserved_dword_candidates[0].raw_u32_hex,
"0x01020304"
);
assert_eq!(
triplet_probe.entries[1].policy_reserved_dword_candidates[2].raw_u32_hex,
"0x05060708"
);
assert!(triplet_probe.evidence.iter().any(|line| line.contains(
"fixed 0x55f2 policy reserved dwords are nonzero on 1 of 2 decoded region records"
)));
}
#[test]
fn parses_region_profile_collection_probe_from_fixed_name_rows() {
let mut payload = vec![0u8; 0x80];
let header_words = [1u32, 0x22, 2, 2, 3, 2, 0, 1];
for (index, word) in header_words.into_iter().enumerate() {
let offset = index * 4;
payload[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let first_row_offset = 0x20usize;
let first_name = b"House";
payload[first_row_offset..first_row_offset + first_name.len()].copy_from_slice(first_name);
payload[first_row_offset + 0x1e..first_row_offset + 0x22]
.copy_from_slice(&0.2f32.to_bits().to_le_bytes());
let second_row_offset = first_row_offset + 0x22;
let second_name = b"Farm Corn";
payload[second_row_offset..second_row_offset + second_name.len()]
.copy_from_slice(second_name);
payload[second_row_offset + 0x1e..second_row_offset + 0x22]
.copy_from_slice(&0.45f32.to_bits().to_le_bytes());
let profile_probe = parse_save_region_profile_collection_probe(&payload)
.expect("profile collection probe should parse");
assert_eq!(profile_probe.direct_collection_flag, 1);
assert_eq!(profile_probe.entry_stride, 0x22);
assert_eq!(profile_probe.live_id_bound, 3);
assert_eq!(profile_probe.live_record_count, 2);
assert_eq!(profile_probe.entry_start_relative_offset, 0x20);
assert_eq!(profile_probe.entries.len(), 2);
assert_eq!(profile_probe.entries[0].name, "House");
assert_eq!(profile_probe.entries[0].trailing_weight_f32, 0.2);
assert_eq!(profile_probe.entries[1].name, "Farm Corn");
assert_eq!(profile_probe.entries[1].trailing_weight_f32, 0.45);
}
#[test]
fn parses_region_queued_notice_record_probe_from_seeded_node() {
let mut bytes = vec![0u8; 0x200];
let node_base_offset = 0x80usize;
bytes[node_base_offset + 4..node_base_offset + 8]
.copy_from_slice(&SAVE_REGION_QUEUED_NOTICE_PAYLOAD_SEED.to_le_bytes());
bytes[node_base_offset + 8..node_base_offset + 12]
.copy_from_slice(&SAVE_REGION_QUEUED_NOTICE_NODE_KIND.to_le_bytes());
bytes[node_base_offset + 12..node_base_offset + 16].copy_from_slice(&0u32.to_le_bytes());
bytes[node_base_offset + 16..node_base_offset + 20].copy_from_slice(&5u32.to_le_bytes());
bytes[node_base_offset + 20..node_base_offset + 24].copy_from_slice(&1200u32.to_le_bytes());
bytes[node_base_offset + 24..node_base_offset + 28].copy_from_slice(&(-1i32).to_le_bytes());
bytes[node_base_offset + 28..node_base_offset + 32].copy_from_slice(&(-1i32).to_le_bytes());
let probe = parse_save_region_queued_notice_record_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-region-tagged-header-counts".to_string(),
semantic_family: "scenario-save-region-header-counts".to_string(),
metadata_tag_offset: 0,
records_tag_offset: 0,
close_tag_offset: 0,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x96,
live_id_bound_hex: "0x00000096".to_string(),
live_record_count: 0x91,
live_record_count_hex: "0x00000091".to_string(),
header_words: vec![],
header_hex_words: vec![],
evidence: vec![],
}),
)
.expect("region queued notice record probe should parse");
assert_eq!(probe.entries.len(), 1);
assert_eq!(probe.entries[0].node_base_offset, node_base_offset);
assert_eq!(probe.entries[0].payload_seed_dword_hex, "0x005c87a8");
assert_eq!(probe.entries[0].kind, SAVE_REGION_QUEUED_NOTICE_NODE_KIND);
assert_eq!(probe.entries[0].region_id, 5);
assert_eq!(probe.entries[0].amount, 1200);
assert_eq!(probe.entries[0].trailing_sentinel_i32_0, -1);
assert_eq!(probe.entries[0].trailing_sentinel_i32_1, -1);
}
#[test]
fn parses_region_fixed_row_run_candidate_probe_from_seeded_rows() {
let mut bytes = vec![0u8; 0x200];
let count_offset = 0x20usize;
let rows_offset = count_offset + 4;
let metadata_tag_offset = 0x120usize;
bytes[count_offset..count_offset + 4].copy_from_slice(&2u32.to_le_bytes());
let first_row = rows_offset;
bytes[first_row..first_row + 4].copy_from_slice(&11u32.to_le_bytes());
bytes[first_row + 4..first_row + 8].copy_from_slice(&0.25f32.to_bits().to_le_bytes());
bytes[first_row + 8..first_row + 12].copy_from_slice(&0x11223344u32.to_le_bytes());
bytes[first_row + 0x28] = 0x07;
let second_row = rows_offset + SAVE_REGION_FIXED_ROW_STRIDE;
bytes[second_row..second_row + 4].copy_from_slice(&12u32.to_le_bytes());
bytes[second_row + 4..second_row + 8].copy_from_slice(&0.5f32.to_bits().to_le_bytes());
bytes[second_row + 8..second_row + 12].copy_from_slice(&0x55667788u32.to_le_bytes());
bytes[second_row + 0x28] = 0x08;
let probe = parse_save_region_fixed_row_run_candidate_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-region-tagged-header-counts".to_string(),
semantic_family: "scenario-save-region-header-counts".to_string(),
metadata_tag_offset,
records_tag_offset: 0,
close_tag_offset: 0,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 0x96,
live_id_bound_hex: "0x00000096".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![],
header_hex_words: vec![],
evidence: vec![],
}),
)
.expect("region fixed-row run candidate probe should parse");
assert_eq!(probe.target_row_count, 2);
assert_eq!(probe.target_row_stride, SAVE_REGION_FIXED_ROW_STRIDE);
assert_eq!(probe.candidates.len(), 1);
assert_eq!(probe.candidates[0].count_offset, count_offset);
assert_eq!(probe.candidates[0].rows_offset, rows_offset);
assert_eq!(
probe.candidates[0].best_probable_density_lane_relative_offset_hex,
Some("0x4".to_string())
);
assert_eq!(
probe.candidates[0].dword_lane_summaries[0].small_unsigned_count,
2
);
assert_eq!(
probe.candidates[0].dword_lane_summaries[1].probable_normal_f32_count,
2
);
assert_eq!(probe.candidates[0].trailing_byte_nonzero_count, 2);
assert_eq!(
probe.candidates[0].trailing_byte_sample_values_hex,
vec!["0x07".to_string(), "0x08".to_string()]
);
assert_eq!(
probe.candidates[0].shape_signature,
"pf32=[0x4:2,0x8:2]|small=[0x0:2]|zero=[]|trail=0/2"
);
assert_eq!(
probe.candidates[0].shape_family_signature,
"dense_pf32=[0x4,0x8]|small_nonzero=[0x0,0x4,0x8]|partial_zero=[]|trail_bucket=0/0"
);
}
#[test]
fn parses_placed_structure_record_triplet_probe_from_dual_name_rows() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x260usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000036b1u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000036b2u32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000036b3u32.to_le_bytes());
let mut cursor = records_tag_offset + 4;
for (primary, secondary, lane0, lane1, lane2, lane3, lane4) in [
(
"StationA",
"StationSetA",
43111.92f32,
1385.5f32,
34581.95f32,
0.0f32,
5.9760494f32,
),
(
"StationB",
"StationSetB",
44000.0f32,
1200.0f32,
33000.0f32,
0.0f32,
4.5f32,
),
] {
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
bytes[cursor + 4] = primary.len() as u8;
bytes[cursor + 5..cursor + 5 + primary.len()].copy_from_slice(primary.as_bytes());
let second_len_offset = cursor + 5 + primary.len();
bytes[second_len_offset] = secondary.len() as u8;
bytes[second_len_offset + 1..second_len_offset + 1 + secondary.len()]
.copy_from_slice(secondary.as_bytes());
cursor += 0x19;
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&lane0.to_bits().to_le_bytes());
bytes[cursor + 8..cursor + 12].copy_from_slice(&lane1.to_bits().to_le_bytes());
bytes[cursor + 12..cursor + 16].copy_from_slice(&lane2.to_bits().to_le_bytes());
bytes[cursor + 16..cursor + 20].copy_from_slice(&lane3.to_bits().to_le_bytes());
bytes[cursor + 20..cursor + 24].copy_from_slice(&lane4.to_bits().to_le_bytes());
bytes[cursor + 28..cursor + 30].copy_from_slice(&0x0101u16.to_le_bytes());
cursor += 0x1e;
bytes[cursor..cursor + 2]
.copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
bytes[cursor + 4..cursor + 8].copy_from_slice(&0x5dc1u32.to_le_bytes());
let mut payload_cursor = cursor + 8;
bytes[payload_cursor] = primary.len() as u8;
bytes[payload_cursor + 1..payload_cursor + 1 + primary.len()]
.copy_from_slice(primary.as_bytes());
payload_cursor += 1 + primary.len();
bytes[payload_cursor] = 0;
payload_cursor += 1;
bytes[payload_cursor] = secondary.len() as u8;
bytes[payload_cursor + 1..payload_cursor + 1 + secondary.len()]
.copy_from_slice(secondary.as_bytes());
payload_cursor += 1 + secondary.len();
bytes[payload_cursor] = 0;
payload_cursor += 1;
bytes[payload_cursor..payload_cursor + 4].copy_from_slice(&0x0e373500u32.to_le_bytes());
bytes[payload_cursor + 4..payload_cursor + 8].copy_from_slice(&(-1i32).to_le_bytes());
bytes[payload_cursor + 8..payload_cursor + 12]
.copy_from_slice(&0x5dc2u32.to_le_bytes());
cursor += 0x18 + primary.len() + secondary.len();
}
let header_probe = SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-tagged-header-counts".to_string(),
semantic_family: "scenario-save-placed-structure-header-counts".to_string(),
metadata_tag_offset,
records_tag_offset,
close_tag_offset,
direct_collection_flag: 0,
direct_collection_flag_hex: "0x00000000".to_string(),
direct_record_stride: 0x06,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 3,
live_id_bound_hex: "0x00000003".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![0, 6, 0x0a, 0x14, 3, 2],
header_hex_words: vec![],
evidence: vec![],
};
let triplet_probe =
parse_save_placed_structure_record_triplet_probe(&bytes, Some(&header_probe))
.expect("placed-structure triplet probe should parse");
assert_eq!(triplet_probe.record_count, 2);
assert_eq!(triplet_probe.entries[0].primary_name, "StationA");
assert_eq!(triplet_probe.entries[0].secondary_name, "StationSetA");
assert_eq!(triplet_probe.entries[0].policy_chunk_len, 0x1a);
assert_eq!(triplet_probe.entries[0].policy_f32_lane_4, 5.9760494);
assert_eq!(triplet_probe.entries[0].policy_trailing_word, 0x0101);
assert_eq!(
triplet_probe.entries[0].profile_open_marker_hex,
"0x00005dc1"
);
assert_eq!(
triplet_probe.entries[0].profile_repeated_primary_name,
"StationA"
);
assert_eq!(
triplet_probe.entries[0].profile_repeated_secondary_name,
"StationSetA"
);
assert_eq!(
triplet_probe.entries[0].profile_payload_dword_hex,
"0x0e373500"
);
assert_eq!(triplet_probe.entries[0].profile_sentinel_i32, -1);
assert_eq!(triplet_probe.entries[0].profile_status_kind, "unset");
assert_eq!(triplet_probe.entries[0].farm_growth_stage_index, None);
assert_eq!(
triplet_probe.entries[0].profile_close_marker_hex,
"0x00005dc2"
);
assert_eq!(triplet_probe.entries[1].primary_name, "StationB");
assert_eq!(triplet_probe.entries[1].secondary_name, "StationSetB");
assert_eq!(triplet_probe.entries[1].policy_f32_lane_1, 1200.0);
}
#[test]
fn derives_placed_structure_farm_growth_stage_from_nonnegative_status() {
assert_eq!(
derive_save_placed_structure_profile_status("FarmCorn", "FarmSet", 4),
("farm_growth_stage_bucket", Some(4))
);
assert_eq!(
derive_save_placed_structure_profile_status("StationA", "StationSetA", -1),
("unset", None)
);
assert_eq!(
derive_save_placed_structure_profile_status("StationA", "StationSetA", 4),
("opaque_nondefault", None)
);
}
#[test]
fn parses_placed_structure_dynamic_side_buffer_probe_from_embedded_name_row() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x220usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000038a5u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000038a6u32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes());
let header_words = [
0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let payload_offset = records_tag_offset + 4;
bytes[payload_offset..payload_offset + 4].copy_from_slice(&0x0005d368u32.to_le_bytes());
bytes[payload_offset + 4..payload_offset + 6].copy_from_slice(&0x0001u16.to_le_bytes());
bytes[payload_offset + 6] = 0xff;
let name_tag_offset = payload_offset + 7;
bytes[name_tag_offset..name_tag_offset + 2]
.copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
let first_name = "TrackCapST_Cap.3dp";
let second_name = "Infrastructure";
bytes[name_tag_offset + 4] = first_name.len() as u8;
bytes[name_tag_offset + 5..name_tag_offset + 5 + first_name.len()]
.copy_from_slice(first_name.as_bytes());
let second_len_offset = name_tag_offset + 5 + first_name.len();
bytes[second_len_offset] = second_name.len() as u8;
bytes[second_len_offset + 1..second_len_offset + 1 + second_name.len()]
.copy_from_slice(second_name.as_bytes());
let probe = parse_save_placed_structure_dynamic_side_buffer_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("placed-structure dynamic side-buffer probe should parse");
assert_eq!(probe.direct_record_stride, 0x06);
assert_eq!(probe.live_id_bound, 1000);
assert_eq!(probe.live_record_count, 388);
assert_eq!(probe.owner_shared_dword_hex, "0x0005d368");
assert_eq!(probe.owner_shared_dword_relative_offset, 0);
assert!(probe.owner_shared_dword_matches_first_compact_prefix_leading_dword);
assert_eq!(probe.first_record_child_count_after_owner_shared, Some(1));
assert_eq!(
probe
.first_record_saved_primary_child_byte_after_owner_shared_hex
.as_deref(),
Some("0xff")
);
assert_eq!(
probe.first_record_first_name_tag_relative_offset_after_owner_shared,
Some(3)
);
assert_eq!(probe.prefix_leading_dword_hex, "0x0005d368");
assert_eq!(probe.prefix_trailing_word_hex, "0x0001");
assert_eq!(probe.prefix_separator_byte_hex, "0xff");
assert_eq!(probe.first_embedded_name_tag_relative_offset, 7);
assert_eq!(probe.embedded_name_tag_count, 1);
assert_eq!(probe.decoded_embedded_name_row_count, 1);
assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
assert_eq!(probe.unique_compact_prefix_pattern_count, 1);
assert_eq!(
probe.prefix_leading_dword_matching_embedded_profile_tag_count,
0
);
assert_eq!(probe.unique_embedded_name_pair_count, 1);
assert_eq!(
probe.first_embedded_primary_name.as_deref(),
Some("TrackCapST_Cap.3dp")
);
assert_eq!(
probe.first_embedded_secondary_name.as_deref(),
Some("Infrastructure")
);
assert_eq!(probe.first_embedded_tertiary_name.as_deref(), None);
assert_eq!(probe.compact_prefix_pattern_summaries.len(), 1);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
"0x0005d368"
);
assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 1);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count,
1
);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count,
0
);
assert_eq!(probe.name_pair_summaries.len(), 1);
assert_eq!(probe.name_pair_summaries[0].count, 1);
assert_eq!(
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
"0x0005d368"
);
let payload_envelope_summary = probe
.payload_envelope_summary
.as_ref()
.expect("payload envelope summary should be present");
assert_eq!(
payload_envelope_summary.row_count_with_policy_tag_before_next_name,
0
);
assert_eq!(
payload_envelope_summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
0
);
assert_eq!(
payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
1
);
}
#[test]
fn summarizes_placed_structure_dynamic_side_buffer_compact_prefix_patterns() {
let mut bytes = vec![0u8; 0x600];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x320usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000038a5u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000038a6u32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000038a7u32.to_le_bytes());
let header_words = [
0u32, 0x06, 1000, 500, 1000, 388, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let mut cursor = records_tag_offset + 4;
for (leading_dword, primary_name) in [
(0x000055f3u32, "TunnelSTBrick_Section.3dp"),
(0x000055f3u32, "TunnelSTBrick_Cap.3dp"),
(0xff0000ffu32, "TunnelSTBrick_Cap.3dp"),
] {
bytes[cursor..cursor + 4].copy_from_slice(&leading_dword.to_le_bytes());
bytes[cursor + 4..cursor + 6].copy_from_slice(&0x0001u16.to_le_bytes());
bytes[cursor + 6] = 0xff;
let name_tag_offset = cursor + 7;
bytes[name_tag_offset..name_tag_offset + 2]
.copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
let secondary_name = "Infrastructure";
bytes[name_tag_offset + 4] = primary_name.len() as u8;
bytes[name_tag_offset + 5..name_tag_offset + 5 + primary_name.len()]
.copy_from_slice(primary_name.as_bytes());
let second_len_offset = name_tag_offset + 5 + primary_name.len();
bytes[second_len_offset] = secondary_name.len() as u8;
bytes[second_len_offset + 1..second_len_offset + 1 + secondary_name.len()]
.copy_from_slice(secondary_name.as_bytes());
cursor = second_len_offset + 1 + secondary_name.len();
}
let probe = parse_save_placed_structure_dynamic_side_buffer_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("placed-structure dynamic side-buffer probe should parse");
assert_eq!(probe.embedded_name_tag_count, 3);
assert_eq!(probe.decoded_embedded_name_row_count, 3);
assert_eq!(probe.decoded_embedded_name_row_with_tertiary_name_count, 0);
assert_eq!(probe.unique_compact_prefix_pattern_count, 2);
assert_eq!(
probe.prefix_leading_dword_matching_embedded_profile_tag_count,
2
);
assert_eq!(probe.unique_embedded_name_pair_count, 2);
assert_eq!(probe.compact_prefix_pattern_summaries.len(), 2);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].prefix_leading_dword_hex,
"0x000055f3"
);
assert_eq!(probe.compact_prefix_pattern_summaries[0].count, 2);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].section_like_primary_name_count,
1
);
assert_eq!(
probe.compact_prefix_pattern_summaries[0].cap_like_primary_name_count,
1
);
assert!(
probe.compact_prefix_pattern_summaries[0]
.prefix_leading_dword_matches_embedded_profile_tag
);
assert_eq!(
probe.compact_prefix_pattern_summaries[1].prefix_leading_dword_hex,
"0xff0000ff"
);
assert_eq!(probe.compact_prefix_pattern_summaries[1].count, 1);
assert_eq!(probe.name_pair_summaries.len(), 2);
assert_eq!(probe.name_pair_summaries[0].count, 2);
assert_eq!(
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
"0x000055f3"
);
assert_eq!(probe.name_pair_summaries[1].count, 1);
let payload_envelope_summary = probe
.payload_envelope_summary
.as_ref()
.expect("payload envelope summary should be present");
assert_eq!(
payload_envelope_summary.row_count_with_policy_tag_before_next_name,
0
);
assert_eq!(
payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
3
);
}
#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_optional_third_name() {
let bytes = [
5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5,
b'T', b'h', b'i', b'r', b'd',
];
let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
.expect("triplet parser should decode three len-prefixed ascii names");
assert_eq!(parsed.0, "First");
assert_eq!(parsed.1, "Second");
assert_eq!(parsed.2.as_deref(), Some("Third"));
}
#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_extended_length_prefix() {
let mut bytes = Vec::new();
bytes.extend_from_slice(&[0x80, 0x03, b'A', b'B', b'C']);
bytes.extend_from_slice(&[0, 1, b'X']);
let parsed = parse_save_len_prefixed_ascii_name_triplet(&bytes)
.expect("triplet parser should decode extended-length prefix");
assert_eq!(parsed.0, "ABC");
assert_eq!(parsed.1, "X");
assert_eq!(parsed.2, None);
}
#[test]
fn parses_save_len_prefixed_ascii_name_triplet_with_consumed_len() {
let bytes = [
5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5,
b'T', b'h', b'i', b'r', b'd', 0xff,
];
let (parsed, consumed_len) =
parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(&bytes)
.expect("triplet parser should decode consumed len");
assert_eq!(parsed.0, "First");
assert_eq!(parsed.1, "Second");
assert_eq!(parsed.2.as_deref(), Some("Third"));
assert_eq!(consumed_len, 21);
}
#[test]
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
semantic_family: "scenario-save-placed-structure-dynamic-side-buffer-records"
.to_string(),
metadata_tag_offset: 0,
records_tag_offset: 0,
close_tag_offset: 0,
records_span_len: 0,
direct_record_stride: 6,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 1000,
live_id_bound_hex: "0x000003e8".to_string(),
live_record_count: 10,
live_record_count_hex: "0x0000000a".to_string(),
owner_shared_dword: 0,
owner_shared_dword_hex: "0x00000000".to_string(),
owner_shared_dword_relative_offset: 0,
owner_shared_dword_matches_first_compact_prefix_leading_dword: true,
first_record_child_count_after_owner_shared: None,
first_record_child_count_after_owner_shared_hex: None,
first_record_saved_primary_child_byte_after_owner_shared: None,
first_record_saved_primary_child_byte_after_owner_shared_hex: None,
first_record_first_name_tag_relative_offset_after_owner_shared: None,
prefix_leading_dword: 0,
prefix_leading_dword_hex: "0x00000000".to_string(),
prefix_trailing_word: 1,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
first_embedded_name_tag_relative_offset: 7,
embedded_name_tag_count: 3,
decoded_embedded_name_row_count: 3,
decoded_embedded_name_row_with_tertiary_name_count: 0,
unique_compact_prefix_pattern_count: 2,
prefix_leading_dword_matching_embedded_profile_tag_count: 2,
unique_embedded_name_pair_count: 2,
first_embedded_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
first_embedded_secondary_name: Some("Infrastructure".to_string()),
first_embedded_tertiary_name: None,
embedded_name_row_samples: vec![],
compact_prefix_pattern_summaries: vec![],
name_pair_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name: "TunnelSTBrick_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
count: 2,
first_name_tag_relative_offset: 7,
unique_compact_prefix_pattern_count: 1,
dominant_prefix_leading_dword: 0x55f3,
dominant_prefix_leading_dword_hex: "0x000055f3".to_string(),
dominant_prefix_trailing_word: 1,
dominant_prefix_trailing_word_hex: "0x0001".to_string(),
dominant_prefix_separator_byte: 0xff,
dominant_prefix_separator_byte_hex: "0xff".to_string(),
dominant_prefix_count: 2,
},
SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name: "BridgeSTWood_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
count: 1,
first_name_tag_relative_offset: 27,
unique_compact_prefix_pattern_count: 1,
dominant_prefix_leading_dword: 0xff000000,
dominant_prefix_leading_dword_hex: "0xff000000".to_string(),
dominant_prefix_trailing_word: 1,
dominant_prefix_trailing_word_hex: "0x0001".to_string(),
dominant_prefix_separator_byte: 0xff,
dominant_prefix_separator_byte_hex: "0xff".to_string(),
dominant_prefix_count: 1,
},
],
payload_envelope_summary: None,
live_entry_prelude_summary: None,
evidence: vec![],
};
let triplets = SmpSavePlacedStructureRecordTripletProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-placed-structure-record-triplets".to_string(),
semantic_family: "scenario-save-placed-structure-record-triplets".to_string(),
records_tag_offset: 0,
close_tag_offset: 0,
record_count: 2,
entries: vec![
SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: 0,
primary_name: "TunnelSTBrick_Section.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0,
profile_chunk_len: 0,
policy_f32_lane_0: 0.0,
policy_f32_lane_1: 0.0,
policy_f32_lane_2: 0.0,
policy_f32_lane_3: 0.0,
policy_f32_lane_4: 0.0,
policy_reserved_dword: 0,
policy_trailing_word: 0,
policy_trailing_word_hex: "0x0000".to_string(),
profile_open_marker: 0,
profile_open_marker_hex: "0x00000000".to_string(),
profile_repeated_primary_name: "TunnelSTBrick_Section.3dp".to_string(),
profile_repeated_secondary_name: "Infrastructure".to_string(),
profile_payload_dword: 0,
profile_payload_dword_hex: "0x00000000".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0,
profile_close_marker_hex: "0x00000000".to_string(),
},
SmpSavePlacedStructureRecordTripletEntryProbe {
record_index: 1,
primary_name: "TrackCapST_Cap.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
name_tag_relative_offset: 0,
policy_tag_relative_offset: 0,
profile_tag_relative_offset: 0,
policy_chunk_len: 0,
profile_chunk_len: 0,
policy_f32_lane_0: 0.0,
policy_f32_lane_1: 0.0,
policy_f32_lane_2: 0.0,
policy_f32_lane_3: 0.0,
policy_f32_lane_4: 0.0,
policy_reserved_dword: 0,
policy_trailing_word: 0,
policy_trailing_word_hex: "0x0000".to_string(),
profile_open_marker: 0,
profile_open_marker_hex: "0x00000000".to_string(),
profile_repeated_primary_name: "TrackCapST_Cap.3dp".to_string(),
profile_repeated_secondary_name: "Infrastructure".to_string(),
profile_payload_dword: 0,
profile_payload_dword_hex: "0x00000000".to_string(),
profile_sentinel_i32: -1,
profile_status_kind: "unset".to_string(),
farm_growth_stage_index: None,
profile_close_marker: 0,
profile_close_marker_hex: "0x00000000".to_string(),
},
],
evidence: vec![],
};
let alignment =
summarize_placed_structure_dynamic_side_buffer_alignment(&side_buffer, &triplets);
assert_eq!(alignment.unique_side_buffer_name_pair_count, 2);
assert_eq!(alignment.unique_triplet_name_pair_count, 2);
assert_eq!(alignment.overlapping_name_pair_count, 1);
assert_eq!(
alignment.side_buffer_rows_with_matching_triplet_name_pair_count,
2
);
assert_eq!(
alignment.side_buffer_rows_without_matching_triplet_name_pair_count,
1
);
assert_eq!(
alignment.triplet_name_pairs_without_side_buffer_match_count,
1
);
assert_eq!(alignment.matched_name_pair_samples.len(), 1);
assert_eq!(alignment.unmatched_side_buffer_name_pair_samples.len(), 1);
}
#[test]
fn parses_placed_structure_tagged_collection_header_probe_from_exact_u32_tags() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x180usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000036b1u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000036b2u32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000036b3u32.to_le_bytes());
let header_words = [
0u32, 0x06, 0x0a, 0x14, 0x7ee, 0x7ea, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let probe = parse_save_placed_structure_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("placed structure header probe should parse");
assert_eq!(probe.metadata_tag_offset, metadata_tag_offset);
assert_eq!(probe.records_tag_offset, records_tag_offset);
assert_eq!(probe.close_tag_offset, close_tag_offset);
assert_eq!(probe.direct_collection_flag, 0);
assert_eq!(probe.direct_record_stride, 0x06);
assert_eq!(probe.live_id_bound, 0x7ee);
assert_eq!(probe.live_record_count, 0x7ea);
}
#[test]
fn scans_unclassified_tagged_collection_header_probe_from_adjacent_low_tags() {
let mut bytes = vec![0u8; 0x400];
let metadata_tag_offset = 0x40usize;
let records_tag_offset = 0x140usize;
let close_tag_offset = 0x1c0usize;
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00007001u32.to_le_bytes());
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x00007002u32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x00007003u32.to_le_bytes());
let header_words = [
0u32, 0x12, 0x0a, 0x14, 0x90, 0x78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let probes = scan_save_unclassified_tagged_collection_header_probes(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
);
let probe = probes
.iter()
.find(|probe| probe.metadata_tag == 0x7001)
.expect("should include synthetic unclassified tag family");
assert_eq!(probe.records_tag, 0x7002);
assert_eq!(probe.close_tag, 0x7003);
assert_eq!(probe.direct_record_stride, 0x12);
assert_eq!(probe.live_id_bound, 0x90);
assert_eq!(probe.live_record_count, 0x78);
assert_eq!(
probe.records_span_len,
close_tag_offset - (records_tag_offset + 4)
);
}
#[test]
fn parses_save_company_roster_probe_from_direct_records() {
let metadata_tag_offset = 0x40usize;
let stride = 0x7684usize;
let count = 2usize;
let start_offset = 0xc6usize;
let total_len = metadata_tag_offset + 4 + start_offset + stride * count + 0x400;
let mut bytes = vec![0u8; total_len];
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x000061a9u32.to_le_bytes());
let header_words = [
1u32,
0x7684,
5,
5,
5,
count as u32,
1,
1,
0,
0,
1,
1,
1,
0,
0,
0,
0,
0,
0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let records_tag_offset = metadata_tag_offset + 4 + 0x200;
let close_tag_offset = records_tag_offset + 4;
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x000061aau32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000061abu32.to_le_bytes());
for (
index,
(
name,
linked,
merger,
takeover,
bond_count,
_debt,
track_capacity,
mutable_support_scalar_raw_u32,
young_company_support_scalar_raw_u32,
support_progress_word,
recent_per_share_subscore_raw_u32,
cached_share_price_raw_u32,
chairman_salary_baseline,
chairman_salary_current,
chairman_bonus_year,
chairman_bonus_amount,
founding_year,
last_bankruptcy_year,
last_dividend_year,
current_issue_calendar_word,
current_issue_calendar_word_2,
prior_issue_calendar_word,
prior_issue_calendar_word_2,
preferred_locomotive_engine_type_raw_u8,
city_connection_latch,
linked_transit_latch,
),
) in [
(
"Company One",
1u32,
1862u32,
1865u32,
2u8,
1_000_000u32,
Some(603i32),
0x3f800000u32,
0x42340000u32,
17u32,
0x41f00000u32,
0x426c0000u32,
24u32,
31u32,
1849u32,
1250i32,
1842u32,
1851u32,
1848u32,
7u32,
8u32,
6u32,
7u32,
2u8,
true,
false,
),
(
"Company Two",
2u32,
0u32,
1871u32,
1u8,
500_000u32,
None,
0x40000000u32,
0x42700000u32,
33u32,
0x42000000u32,
0x42780000u32,
28u32,
36u32,
0u32,
0i32,
1845u32,
0u32,
1850u32,
3u32,
4u32,
2u32,
3u32,
1u8,
false,
true,
),
]
.into_iter()
.enumerate()
{
let record_offset = metadata_tag_offset + 4 + start_offset + index * stride;
bytes[record_offset..record_offset + 4]
.copy_from_slice(&((index + 1) as u32).to_le_bytes());
bytes[record_offset + 4..record_offset + 4 + name.len()]
.copy_from_slice(name.as_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET
..record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET + 4]
.copy_from_slice(&linked.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_ACTIVE_OFFSET] = 1;
bytes[record_offset + 0x47..record_offset + 0x4b]
.copy_from_slice(&20000u32.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET + 4]
.copy_from_slice(&mutable_support_scalar_raw_u32.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET
..record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET + 4]
.copy_from_slice(&young_company_support_scalar_raw_u32.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET] = bond_count;
for slot_index in 0..bond_count as usize {
let slot_offset = record_offset
+ SAVE_COMPANY_RECORD_BOND_TABLE_OFFSET
+ slot_index * SAVE_COMPANY_RECORD_BOND_SLOT_STRIDE;
let (principal, coupon_rate) = if index == 0 && slot_index == 0 {
(900_000i32, 0.08f32)
} else if index == 0 && slot_index == 1 {
(650_000i32, 0.12f32)
} else {
(500_000i32, 0.10f32)
};
bytes[slot_offset..slot_offset + 4].copy_from_slice(&principal.to_le_bytes());
bytes[slot_offset + 4..slot_offset + 8]
.copy_from_slice(&(1894u32 + slot_index as u32).to_le_bytes());
bytes[slot_offset + 8..slot_offset + 12]
.copy_from_slice(&coupon_rate.to_le_bytes());
}
bytes[record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET
..record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET + 4]
.copy_from_slice(&merger.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET
..record_offset + SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET + 4]
.copy_from_slice(&takeover.to_le_bytes());
let raw_capacity = track_capacity.unwrap_or(-1);
bytes[record_offset + SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET
..record_offset + SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET + 4]
.copy_from_slice(&raw_capacity.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET
..record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET + 4]
.copy_from_slice(&support_progress_word.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET
..record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET + 4]
.copy_from_slice(&recent_per_share_subscore_raw_u32.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET + 4]
.copy_from_slice(&cached_share_price_raw_u32.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET + 4]
.copy_from_slice(&chairman_salary_baseline.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET + 4]
.copy_from_slice(&chairman_salary_current.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_YEAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_YEAR_OFFSET + 4]
.copy_from_slice(&chairman_bonus_year.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_AMOUNT_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_BONUS_AMOUNT_OFFSET + 4]
.copy_from_slice(&chairman_bonus_amount.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET + 4]
.copy_from_slice(&founding_year.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET + 4]
.copy_from_slice(&last_bankruptcy_year.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_LAST_DIVIDEND_YEAR_OFFSET + 4]
.copy_from_slice(&last_dividend_year.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET + 4]
.copy_from_slice(&current_issue_calendar_word.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET_2
..record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET_2 + 4]
.copy_from_slice(&current_issue_calendar_word_2.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET
..record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET + 4]
.copy_from_slice(&prior_issue_calendar_word.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET_2
..record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET_2 + 4]
.copy_from_slice(&prior_issue_calendar_word_2.to_le_bytes());
bytes[record_offset + SAVE_COMPANY_RECORD_PREFERRED_LOCOMOTIVE_ENGINE_TYPE_OFFSET] =
preferred_locomotive_engine_type_raw_u8;
bytes[record_offset + SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET] =
u8::from(city_connection_latch);
bytes[record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET] =
u8::from(linked_transit_latch);
let current_cash: f64 = if index == 0 { 125_000.0 } else { -25_000.0 };
let current_cash_slot_offset = record_offset
+ SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET
+ (crate::RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH as usize
* crate::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN as usize
* 8);
bytes[current_cash_slot_offset..current_cash_slot_offset + 8]
.copy_from_slice(&current_cash.to_bits().to_le_bytes());
}
let header_probe = parse_save_company_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("company header probe should parse");
let roster = parse_save_company_roster_probe(
&bytes,
Some(&header_probe),
Some(&SmpSaveWorldSelectionContextProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-selected-company-and-chairman-context".to_string(),
chunk_tag_offset: 0,
payload_offset: 0,
payload_len: 0,
payload_len_hex: "0x0".to_string(),
selected_company_id_offset: 0,
selected_company_id: 2,
selected_company_id_hex: "0x00000002".to_string(),
selected_chairman_profile_id_offset: 0,
selected_chairman_profile_id: 1,
selected_chairman_profile_id_hex: "0x00000001".to_string(),
chairman_slot_selector_offset: 0,
chairman_slot_selectors: vec![],
campaign_override_flag_offset: 0,
campaign_override_flag: 0,
campaign_override_flag_hex: "0x00".to_string(),
chairman_role_gate_offset: 0,
chairman_role_gate_bytes: vec![],
evidence: vec![],
}),
)
.expect("company roster should parse");
assert_eq!(roster.observed_entry_count, 2);
assert_eq!(roster.selected_company_id, Some(2));
assert_eq!(roster.entries.len(), 2);
assert_eq!(roster.entries[0].company_id, 1);
assert_eq!(roster.entries[0].current_cash, 125_000);
assert_eq!(roster.entries[0].linked_chairman_profile_id, Some(1));
assert_eq!(roster.entries[0].debt, 1_550_000);
assert_eq!(roster.entries[0].available_track_laying_capacity, Some(603));
assert_eq!(roster.entries[0].merger_cooldown_year, Some(1862));
let market_state = roster.entries[0]
.market_state
.as_ref()
.expect("company market state should load");
assert_eq!(market_state.outstanding_shares, 20_000);
assert_eq!(market_state.live_bond_slots.len(), 2);
assert_eq!(market_state.live_bond_slots[0].principal, 900_000);
assert_eq!(market_state.live_bond_slots[0].maturity_year, 1894);
assert_eq!(
market_state.live_bond_slots[1].coupon_rate_raw_u32,
0.12f32.to_bits()
);
assert_eq!(market_state.largest_live_bond_principal, Some(900_000));
assert_eq!(
market_state.highest_coupon_live_bond_principal,
Some(650_000)
);
assert_eq!(market_state.mutable_support_scalar_raw_u32, 0x3f800000);
assert_eq!(
market_state.young_company_support_scalar_raw_u32,
0x42340000
);
assert_eq!(market_state.support_progress_word, 17);
assert_eq!(market_state.recent_per_share_subscore_raw_u32, 0x41f00000);
assert_eq!(market_state.cached_share_price_raw_u32, 0x426c0000);
assert_eq!(market_state.chairman_salary_baseline, 24);
assert_eq!(market_state.chairman_salary_current, 31);
assert_eq!(market_state.chairman_bonus_year, 1849);
assert_eq!(market_state.chairman_bonus_amount, 1250);
assert_eq!(market_state.founding_year, 1842);
assert_eq!(market_state.last_bankruptcy_year, 1851);
assert_eq!(market_state.last_dividend_year, 1848);
assert_eq!(market_state.current_issue_calendar_word, 7);
assert_eq!(market_state.current_issue_calendar_word_2, 8);
assert_eq!(market_state.prior_issue_calendar_word, 6);
assert_eq!(market_state.prior_issue_calendar_word_2, 7);
assert_eq!(
roster.entries[0].preferred_locomotive_engine_type_raw_u8,
Some(2)
);
assert!(market_state.city_connection_latch);
assert!(!market_state.linked_transit_latch);
assert_eq!(
market_state.stat_band_root_0cfb_candidates.len(),
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS
);
assert_eq!(
market_state.stat_band_root_0d7f_candidates.len(),
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS
);
assert_eq!(
market_state.stat_band_root_1c47_candidates.len(),
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS
);
assert_eq!(
market_state.stat_band_root_0cfb_candidates[31].label,
"stat_band_0cfb_word_32"
);
assert_eq!(
market_state.stat_band_root_0cfb_candidates[31].relative_offset_hex,
"0xd77"
);
assert_eq!(roster.entries[1].company_id, 2);
assert_eq!(roster.entries[1].current_cash, -25_000);
assert_eq!(roster.entries[1].linked_chairman_profile_id, Some(2));
assert_eq!(roster.entries[1].debt, 500_000);
assert_eq!(roster.entries[1].available_track_laying_capacity, None);
assert_eq!(roster.entries[1].takeover_cooldown_year, Some(1871));
let second_market_state = roster.entries[1]
.market_state
.as_ref()
.expect("second company market state should load");
assert_eq!(
second_market_state.largest_live_bond_principal,
Some(500_000)
);
assert_eq!(
second_market_state.highest_coupon_live_bond_principal,
Some(500_000)
);
assert_eq!(second_market_state.chairman_bonus_year, 0);
assert_eq!(second_market_state.chairman_bonus_amount, 0);
assert_eq!(second_market_state.last_dividend_year, 1850);
assert_eq!(second_market_state.current_issue_calendar_word, 3);
assert_eq!(second_market_state.current_issue_calendar_word_2, 4);
assert_eq!(second_market_state.prior_issue_calendar_word, 2);
assert_eq!(second_market_state.prior_issue_calendar_word_2, 3);
assert_eq!(
roster.entries[1].preferred_locomotive_engine_type_raw_u8,
Some(1)
);
assert!(!second_market_state.city_connection_latch);
assert!(second_market_state.linked_transit_latch);
}
#[test]
fn parses_save_chairman_profile_table_probe_from_direct_records() {
let metadata_tag_offset = 0x40usize;
let stride = 0xcabusize;
let count = 2usize;
let start_offset = 0x4eusize;
let total_len = metadata_tag_offset + 4 + start_offset + stride * count + 0x200;
let mut bytes = vec![0u8; total_len];
bytes[metadata_tag_offset..metadata_tag_offset + 4]
.copy_from_slice(&0x00005209u32.to_le_bytes());
let header_words = [
1u32,
0xcab,
8,
6,
8,
count as u32,
1,
1,
0,
0,
1,
1,
1,
0,
0,
0,
0,
0,
0,
];
for (index, word) in header_words.into_iter().enumerate() {
let offset = metadata_tag_offset + 4 + index * 4;
bytes[offset..offset + 4].copy_from_slice(&word.to_le_bytes());
}
let records_tag_offset = metadata_tag_offset + 4 + 0x100;
let close_tag_offset = records_tag_offset + 4;
bytes[records_tag_offset..records_tag_offset + 4]
.copy_from_slice(&0x0000520au32.to_le_bytes());
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
for (index, (name, linked, cash, cache0, cache1, cache4, holdings)) in [
(
"Collis Huntington",
1u32,
-107644.0f64,
252508.0f64,
0.0f64,
0.0f64,
vec![(1u32, 6000u32)],
),
(
"Thomas Durant",
2u32,
-382718.0f64,
-283562.0f64,
822000.0f64,
1_392_000.0f64,
vec![(2u32, 9000u32)],
),
]
.into_iter()
.enumerate()
{
let record_offset = metadata_tag_offset + 4 + start_offset + index * stride;
bytes[record_offset..record_offset + 4]
.copy_from_slice(&((index + 1) as u32).to_le_bytes());
bytes[record_offset + 4..record_offset + 8].copy_from_slice(&1u32.to_le_bytes());
bytes[record_offset + SAVE_CHAIRMAN_RECORD_NAME_OFFSET
..record_offset + SAVE_CHAIRMAN_RECORD_NAME_OFFSET + name.len()]
.copy_from_slice(name.as_bytes());
bytes[record_offset + SAVE_CHAIRMAN_RECORD_CASH_OFFSET
..record_offset + SAVE_CHAIRMAN_RECORD_CASH_OFFSET + 8]
.copy_from_slice(&cash.to_le_bytes());
bytes[record_offset + SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET
..record_offset + SAVE_CHAIRMAN_RECORD_LINKED_COMPANY_OFFSET + 4]
.copy_from_slice(&linked.to_le_bytes());
bytes[record_offset + SAVE_CHAIRMAN_RECORD_PERSONALITY_BYTE_0X291_OFFSET] =
(index as u8) + 10;
bytes[record_offset + SAVE_CHAIRMAN_RECORD_CACHE_0_OFFSET
..record_offset + SAVE_CHAIRMAN_RECORD_CACHE_0_OFFSET + 8]
.copy_from_slice(&cache0.to_le_bytes());
bytes[record_offset + SAVE_CHAIRMAN_RECORD_CACHE_1_OFFSET
..record_offset + SAVE_CHAIRMAN_RECORD_CACHE_1_OFFSET + 8]
.copy_from_slice(&cache1.to_le_bytes());
bytes[record_offset + 0x211..record_offset + 0x211 + 8]
.copy_from_slice(&cache4.to_le_bytes());
for (company_id, units) in holdings {
let slot_offset = record_offset
+ SAVE_CHAIRMAN_RECORD_HOLDINGS_BASE_OFFSET
+ company_id as usize * 4;
bytes[slot_offset..slot_offset + 4].copy_from_slice(&units.to_le_bytes());
}
}
let header_probe = parse_save_chairman_profile_collection_header_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
)
.expect("chairman header probe should parse");
let table = parse_save_chairman_profile_table_probe(
&bytes,
Some(&header_probe),
Some(&SmpSaveWorldSelectionContextProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-selected-company-and-chairman-context".to_string(),
chunk_tag_offset: 0,
payload_offset: 0,
payload_len: 0,
payload_len_hex: "0x0".to_string(),
selected_company_id_offset: 0,
selected_company_id: 2,
selected_company_id_hex: "0x00000002".to_string(),
selected_chairman_profile_id_offset: 0,
selected_chairman_profile_id: 2,
selected_chairman_profile_id_hex: "0x00000002".to_string(),
chairman_slot_selector_offset: 0,
chairman_slot_selectors: vec![],
campaign_override_flag_offset: 0,
campaign_override_flag: 0,
campaign_override_flag_hex: "0x00".to_string(),
chairman_role_gate_offset: 0,
chairman_role_gate_bytes: vec![],
evidence: vec![],
}),
Some(&SmpSaveTaggedCollectionHeaderProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-company-tagged-header-counts".to_string(),
semantic_family: "scenario-save-company-header-counts".to_string(),
metadata_tag_offset: 0,
records_tag_offset: 0,
close_tag_offset: 0,
direct_collection_flag: 1,
direct_collection_flag_hex: "0x00000001".to_string(),
direct_record_stride: 0x7684,
direct_record_stride_hex: "0x00007684".to_string(),
live_id_bound: 5,
live_id_bound_hex: "0x00000005".to_string(),
live_record_count: 2,
live_record_count_hex: "0x00000002".to_string(),
header_words: vec![],
header_hex_words: vec![],
evidence: vec![],
}),
)
.expect("chairman profile table should parse");
assert_eq!(table.observed_entry_count, 2);
assert_eq!(table.selected_chairman_profile_id, Some(2));
assert_eq!(table.entries.len(), 2);
assert_eq!(table.entries[0].profile_id, 1);
assert_eq!(table.entries[0].name, "Collis Huntington");
assert_eq!(table.entries[0].linked_company_id, Some(1));
assert_eq!(table.entries[0].company_holdings.get(&1), Some(&6000));
assert_eq!(table.entries[0].current_cash, -107644);
assert_eq!(table.entries[0].holdings_value_total, 252508);
assert_eq!(table.entries[0].purchasing_power_total, 144864);
assert_eq!(table.entries[0].personality_byte_0x291, Some(10));
assert_eq!(table.entries[1].profile_id, 2);
assert_eq!(table.entries[1].company_holdings.get(&2), Some(&9000));
assert_eq!(table.entries[1].holdings_value_total, 822000);
assert_eq!(table.entries[1].purchasing_power_total, 1_009_282);
assert_eq!(table.entries[1].personality_byte_0x291, Some(11));
}
#[test]
fn builds_save_world_selection_role_analysis_from_probe() {
let probe = SmpSaveWorldSelectionContextProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
source_kind: "save-direct-world-block".to_string(),
semantic_family: "scenario-selected-company-and-chairman-context".to_string(),
chunk_tag_offset: 0,
payload_offset: 0,
payload_len: 0x4f2c,
payload_len_hex: "0x4f2c".to_string(),
selected_company_id_offset: 0x21,
selected_company_id: 3,
selected_company_id_hex: "0x00000003".to_string(),
selected_chairman_profile_id_offset: 0x25,
selected_chairman_profile_id: 7,
selected_chairman_profile_id_hex: "0x00000007".to_string(),
chairman_slot_selector_offset: 0x87,
chairman_slot_selectors: vec![1, 0, 2, 0],
campaign_override_flag_offset: 0xc5,
campaign_override_flag: 1,
campaign_override_flag_hex: "0x01".to_string(),
chairman_role_gate_offset: 0x0bc3,
chairman_role_gate_bytes: vec![2, 0, 1, 0],
evidence: vec![],
};
let analysis = build_save_world_selection_role_analysis(&probe);
assert_eq!(analysis.selected_company_id, 3);
assert_eq!(analysis.selected_chairman_profile_id, 7);
assert_eq!(analysis.campaign_override_flag_hex, "0x01");
assert_eq!(analysis.chairman_slots.len(), 4);
assert_eq!(analysis.chairman_slots[0].selector_byte_hex, "0x01");
assert_eq!(analysis.chairman_slots[2].role_gate_byte_hex, "0x01");
}
#[test]
fn builds_save_candidate_views_with_raw_bits() {
let mut bytes = vec![0u8; 0x40];
bytes[0x08..0x0c].copy_from_slice(&0x3f800000u32.to_le_bytes());
bytes[0x10..0x18].copy_from_slice(&(-2458.0f64).to_le_bytes());
let dword = build_save_dword_candidate(&bytes, 0, "unit_float", 0x08)
.expect("dword candidate should build");
let qword =
build_save_qword_candidate(&bytes, 0, 0x10).expect("qword candidate should build");
assert_eq!(dword.raw_u32_hex, "0x3f800000");
assert_eq!(dword.value_i32, 1_065_353_216);
assert_eq!(dword.value_f32, 1.0);
assert_eq!(qword.raw_u64, (-2458.0f64).to_bits());
assert_eq!(qword.value_i64, (-2458.0f64).to_bits() as i64);
assert_eq!(qword.value_f64, -2458.0);
}
#[test]
fn derives_chairman_holdings_share_price_total_from_grounded_company_prices() {
let holdings_by_company =
BTreeMap::from([(2u32, 19_000u32), (4u32, 1_000u32), (6u32, 2_000u32)]);
let company_share_prices = BTreeMap::from([(2u32, 66i64), (4u32, 69i64), (6u32, 27i64)]);
let total =
derive_chairman_holdings_share_price_total(&holdings_by_company, &company_share_prices)
.expect("derived holdings total should compute");
assert_eq!(total, 1_377_000);
}
#[test]
fn derives_chairman_cached_purchasing_power_from_strongest_nonnegative_cache() {
let cached_scalar_candidates = vec![
SmpSaveScalarCandidate {
relative_offset: 0x1e9,
relative_offset_hex: "0x1e9".to_string(),
raw_u64: (-343_508.0f64).to_bits(),
raw_u64_hex: format!("0x{:016x}", (-343_508.0f64).to_bits()),
value_i64: round_f64_to_i64(-343_508.0).expect("i64"),
value_f64: -343_508.0,
},
SmpSaveScalarCandidate {
relative_offset: 0x201,
relative_offset_hex: "0x201".to_string(),
raw_u64: 1_386_000.0f64.to_bits(),
raw_u64_hex: format!("0x{:016x}", 1_386_000.0f64.to_bits()),
value_i64: round_f64_to_i64(1_386_000.0).expect("i64"),
value_f64: 1_386_000.0,
},
SmpSaveScalarCandidate {
relative_offset: 0x211,
relative_offset_hex: "0x211".to_string(),
raw_u64: 1_392_000.0f64.to_bits(),
raw_u64_hex: format!("0x{:016x}", 1_392_000.0f64.to_bits()),
value_i64: round_f64_to_i64(1_392_000.0).expect("i64"),
value_f64: 1_392_000.0,
},
];
let total =
derive_chairman_cached_purchasing_power_total(-463_436, &cached_scalar_candidates)
.expect("derived purchasing power should compute");
assert_eq!(total, 928_564);
}
#[test]
fn classifies_rt3_105_post_span_bridge_variants() {
let base_trailer = SmpRuntimeTrailerBlock {
profile_family: "rt3-105-save-container-v1".to_string(),
trailer_family: "rt3-105-save-trailer-v1".to_string(),
trailer_evidence: vec![],
trailer_offset: 944,
prefix_words_0_to_5: vec![],
prefix_hex_words_0_to_5: vec![],
tag_word_6: 0,
tag_word_6_hex: String::new(),
tag_chunk_id_u16: 0x2ee1,
tag_chunk_id_hex: "0x2ee1".to_string(),
tag_chunk_id_grounded_alignment: None,
length_word_7: 0x32c8_0000,
length_word_7_hex: "0x32c80000".to_string(),
length_high_u16: 0x32c8,
length_high_hex: "0x32c8".to_string(),
selector_word_8: 0x7110_0000,
selector_word_8_hex: "0x71100000".to_string(),
selector_high_u16: 0x7110,
selector_high_hex: "0x7110".to_string(),
layout_word_9: 0,
layout_word_9_hex: String::new(),
descriptor_word_10: 0x7801_0000,
descriptor_word_10_hex: "0x78010000".to_string(),
descriptor_high_u16: 0x7801,
descriptor_high_hex: "0x7801".to_string(),
descriptor_word_11: 0,
descriptor_word_11_hex: String::new(),
counter_word_12: 0,
counter_word_12_hex: String::new(),
offset_word_13: 0,
offset_word_13_hex: String::new(),
span_word_14: 0,
span_word_14_hex: String::new(),
mode_word_15: 0,
mode_word_15_hex: String::new(),
words: vec![],
hex_words: vec![],
};
let base_post_span = SmpRuntimePostSpanProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
span_target_offset: 13944,
next_nonzero_offset: Some(14795),
next_aligned_candidate_offset: Some(20244),
next_aligned_candidate_words: vec![],
next_aligned_candidate_hex_words: vec![],
header_candidates: vec![SmpRuntimePostSpanHeaderCandidate {
offset: 20244,
words: vec![],
hex_words: vec![],
dense_word_count: 3,
high_u16_words: vec![0x6200, 0x0000, 0xfff7, 0x5515],
high_hex_words: vec![],
grounded_alignments: vec![],
}],
grounded_progress_hits: vec![],
};
let base_profile = SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
packed_profile_offset: 29632,
packed_profile_len: 0x108,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
relative_len: 0x108,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 2,
header_flag_word_3: 0x0100_0000,
header_flag_word_3_hex: "0x01000000".to_string(),
map_path_offset: 0x10,
map_path: Some("Alternate USA.gmp".to_string()),
display_name_offset: 0x43,
display_name: Some("Alternate USA".to_string()),
profile_byte_0x77: 0x07,
profile_byte_0x77_hex: "0x07".to_string(),
profile_byte_0x82: 0x4d,
profile_byte_0x82_hex: "0x4d".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
};
let base_bridge = parse_rt3_105_post_span_bridge_probe(
Some(&base_trailer),
Some(&base_post_span),
Some(&base_profile),
)
.expect("base bridge should parse");
assert_eq!(
base_bridge.bridge_family,
"rt3-105-save-post-span-bridge-v1"
);
assert_eq!(base_bridge.packed_profile_delta_from_span_target, 15688);
assert_eq!(
base_bridge.next_candidate_delta_from_packed_profile,
Some(-9388)
);
let base_variant_trailer = SmpRuntimeTrailerBlock {
descriptor_word_10: 0x7401_0000,
descriptor_word_10_hex: "0x74010000".to_string(),
descriptor_high_u16: 0x7401,
descriptor_high_hex: "0x7401".to_string(),
..base_trailer.clone()
};
let base_variant_bridge = parse_rt3_105_post_span_bridge_probe(
Some(&base_variant_trailer),
Some(&base_post_span),
Some(&base_profile),
)
.expect("base bridge variant should parse");
assert_eq!(
base_variant_bridge.bridge_family,
"rt3-105-save-post-span-bridge-v1"
);
let alt_trailer = SmpRuntimeTrailerBlock {
profile_family: "rt3-105-alt-save-container-v1".to_string(),
selector_word_8: 0x54cd_0000,
selector_word_8_hex: "0x54cd0000".to_string(),
selector_high_u16: 0x54cd,
selector_high_hex: "0x54cd".to_string(),
descriptor_word_10: 0x5901_0000,
descriptor_word_10_hex: "0x59010000".to_string(),
descriptor_high_u16: 0x5901,
descriptor_high_hex: "0x5901".to_string(),
..base_trailer.clone()
};
let alt_post_span = SmpRuntimePostSpanProbe {
profile_family: "rt3-105-alt-save-container-v1".to_string(),
next_aligned_candidate_offset: Some(29892),
header_candidates: vec![SmpRuntimePostSpanHeaderCandidate {
offset: 29892,
words: vec![],
hex_words: vec![],
dense_word_count: 3,
high_u16_words: vec![0x1500, 0x0100, 0x4100, 0x0200],
high_hex_words: vec![],
grounded_alignments: vec![],
}],
..base_post_span.clone()
};
let alt_profile = SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-alt-save-container-v1".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
map_path: Some("Spanish Mainline.gmp".to_string()),
display_name: Some("Spanish Mainline".to_string()),
profile_byte_0x82: 0xa3,
profile_byte_0x82_hex: "0xa3".to_string(),
..base_profile.packed_profile_block.clone()
},
..base_profile.clone()
};
let alt_bridge = parse_rt3_105_post_span_bridge_probe(
Some(&alt_trailer),
Some(&alt_post_span),
Some(&alt_profile),
)
.expect("alt bridge should parse");
assert_eq!(
alt_bridge.bridge_family,
"rt3-105-alt-save-post-span-bridge-v1"
);
assert_eq!(
alt_bridge.next_candidate_delta_from_packed_profile,
Some(260)
);
let scenario_trailer = SmpRuntimeTrailerBlock {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
trailer_family: "unknown".to_string(),
trailer_offset: 864,
length_word_7: 0,
length_word_7_hex: "0x00000000".to_string(),
length_high_u16: 0,
length_high_hex: "0x0000".to_string(),
selector_word_8: 0x0001_86a0,
selector_word_8_hex: "0x000186a0".to_string(),
selector_high_u16: 0x0001,
selector_high_hex: "0x0001".to_string(),
descriptor_word_10: 0x0186_a000,
descriptor_word_10_hex: "0x0186a000".to_string(),
descriptor_high_u16: 0x0186,
descriptor_high_hex: "0x0186".to_string(),
..base_trailer.clone()
};
let scenario_post_span = SmpRuntimePostSpanProbe {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
span_target_offset: 864,
next_aligned_candidate_offset: Some(940),
header_candidates: vec![SmpRuntimePostSpanHeaderCandidate {
offset: 940,
words: vec![],
hex_words: vec![],
dense_word_count: 3,
high_u16_words: vec![0x0186, 0x0006, 0x0006, 0x0001],
high_hex_words: vec![],
grounded_alignments: vec![],
}],
..base_post_span.clone()
};
let scenario_profile = SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
map_path: Some("Southern Pacific.gmp".to_string()),
display_name: Some("Southern Pacific".to_string()),
profile_byte_0x82: 0x90,
profile_byte_0x82_hex: "0x90".to_string(),
..base_profile.packed_profile_block.clone()
},
..base_profile.clone()
};
let scenario_bridge = parse_rt3_105_post_span_bridge_probe(
Some(&scenario_trailer),
Some(&scenario_post_span),
Some(&scenario_profile),
)
.expect("scenario bridge should parse");
assert_eq!(
scenario_bridge.bridge_family,
"rt3-105-scenario-post-span-bridge-v1"
);
assert_eq!(
scenario_bridge.next_candidate_delta_from_packed_profile,
Some(-28692)
);
}
#[test]
fn parses_rt3_105_save_bridge_payload_probe() {
let mut bytes = vec![0u8; 0x7000];
let primary = 0x4f14usize;
let secondary = 0x671cusize;
let primary_words: [u32; 8] = [
0x62000000, 0x00000000, 0xfff70000, 0x55150000, 0x55550000, 0x00000000, 0xfff70000,
0x54550000,
];
for (index, word) in primary_words.iter().enumerate() {
bytes[primary + index * 4..primary + (index + 1) * 4]
.copy_from_slice(&(*word).to_le_bytes());
}
let secondary_words: [u32; 8] = [
0x00050000, 0x00050005, 0xfff70000, 0x54540000, 0x545400f9, 0x00f900f9, 0x00f94008,
0x00001555,
];
for (index, word) in secondary_words.iter().enumerate() {
bytes[secondary + index * 4..secondary + (index + 1) * 4]
.copy_from_slice(&(*word).to_le_bytes());
}
let bridge_probe = SmpRt3105PostSpanBridgeProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
bridge_family: "rt3-105-save-post-span-bridge-v1".to_string(),
bridge_evidence: vec![],
span_target_offset: 0x3678,
next_candidate_offset: Some(primary),
next_candidate_delta_from_span_target: Some(primary - 0x3678),
packed_profile_offset: 0x73c0,
packed_profile_delta_from_span_target: 0x3d48,
next_candidate_delta_from_packed_profile: Some(primary as i64 - 0x73c0),
selector_high_u16: 0x7110,
selector_high_hex: "0x7110".to_string(),
descriptor_high_u16: 0x7801,
descriptor_high_hex: "0x7801".to_string(),
next_candidate_high_u16_words: vec![0x6200, 0x0000, 0xfff7, 0x5515],
next_candidate_high_hex_words: vec![],
};
let probe = parse_rt3_105_save_bridge_payload_probe(&bytes, Some(&bridge_probe))
.expect("save bridge payload probe should parse");
assert_eq!(probe.primary_block_offset, primary);
assert_eq!(probe.primary_block_len, 0x20);
assert_eq!(probe.secondary_block_offset, secondary);
assert_eq!(probe.secondary_block_delta_from_primary, 0x1808);
assert_eq!(probe.secondary_block_end_offset, 0x73c0);
assert_eq!(probe.secondary_block_len, 0xca4);
assert_eq!(probe.primary_words[..4], primary_words[..4]);
assert_eq!(probe.secondary_words[..8], secondary_words[..8]);
}
#[test]
fn parses_rt3_105_save_name_table_probe() {
let mut bytes = vec![0u8; 0x7400];
let secondary = 0x671cusize;
let header = secondary + 0x354;
let entries = secondary + 0x3b5;
let stride = 0x22usize;
let names = ["AluminumMill", "Nuclear Power Plant", "Bakery"];
bytes[header..header + 4].copy_from_slice(&0x10000000u32.to_le_bytes());
bytes[header + 4..header + 8].copy_from_slice(&0x00009000u32.to_le_bytes());
bytes[header + 8..header + 12].copy_from_slice(&0x0000332eu32.to_le_bytes());
bytes[header + 0x1c..header + 0x20].copy_from_slice(&4u32.to_le_bytes());
bytes[header + 0x20..header + 0x24].copy_from_slice(&(names.len() as u32).to_le_bytes());
bytes[header + 12..header + 16].copy_from_slice(&1u32.to_le_bytes());
bytes[header + 16..header + 20].copy_from_slice(&0x22u32.to_le_bytes());
bytes[header + 20..header + 24].copy_from_slice(&2u32.to_le_bytes());
bytes[header + 24..header + 28].copy_from_slice(&2u32.to_le_bytes());
bytes[header + 0x28..header + 0x2c].copy_from_slice(&1u32.to_le_bytes());
for (index, name) in names.iter().enumerate() {
let off = entries + index * stride;
let raw = &mut bytes[off..off + stride];
raw[..name.len()].copy_from_slice(name.as_bytes());
let trailer = if *name == "Nuclear Power Plant" {
0u32
} else {
1u32
};
raw[stride - 4..stride].copy_from_slice(&trailer.to_le_bytes());
}
let footer = entries + names.len() * stride;
bytes[footer..footer + 4].copy_from_slice(&0x32dcu32.to_le_bytes());
bytes[footer + 4..footer + 8].copy_from_slice(&0x3714u32.to_le_bytes());
bytes[footer + 8] = 0x00;
let payload = SmpRt3105SaveBridgePayloadProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
bridge_family: "rt3-105-save-post-span-bridge-v1".to_string(),
primary_block_offset: 0x4f14,
primary_block_len: 0x20,
primary_block_len_hex: "0x20".to_string(),
primary_words: vec![],
primary_hex_words: vec![],
secondary_block_offset: secondary,
secondary_block_delta_from_primary: 0x1808,
secondary_block_delta_from_primary_hex: "0x1808".to_string(),
secondary_block_end_offset: footer + 9,
secondary_block_len: footer + 9 - secondary,
secondary_block_len_hex: format!("0x{:x}", footer + 9 - secondary),
secondary_preview_word_count: 32,
secondary_words: vec![],
secondary_hex_words: vec![],
evidence: vec![],
};
let probe = parse_rt3_105_save_name_table_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&payload),
)
.expect("save name table probe should parse");
assert_eq!(probe.source_kind, "save-bridge-secondary-block");
assert_eq!(
probe.semantic_family,
"scenario-named-candidate-availability-table"
);
assert_eq!(probe.header_offset, header);
assert_eq!(probe.entry_stride, stride);
assert_eq!(probe.observed_entry_capacity, 4);
assert_eq!(probe.observed_entry_count, names.len());
assert_eq!(probe.entries[0].text, "AluminumMill");
assert_eq!(probe.entries[0].availability_dword, 1);
assert_eq!(probe.entries[2].text, "Bakery");
assert_eq!(probe.zero_trailer_entry_count, 1);
assert_eq!(
probe.zero_trailer_entry_names,
vec!["Nuclear Power Plant".to_string()]
);
assert_eq!(probe.trailing_footer_hex, "dc3200001437000000");
assert_eq!(probe.footer_progress_word_0, 0x32dc);
assert_eq!(probe.footer_progress_word_1, 0x3714);
assert_eq!(probe.footer_trailing_byte, 0x00);
}
#[test]
fn parses_rt3_105_map_name_table_probe_from_fixed_offsets() {
let mut bytes = vec![0u8; 0x7400];
let header = 0x6a70usize;
let entries = 0x6ad1usize;
let stride = 0x22usize;
let observed_entry_count = 67usize;
bytes[header..header + 4].copy_from_slice(&0x00000000u32.to_le_bytes());
bytes[header + 4..header + 8].copy_from_slice(&0x00000000u32.to_le_bytes());
bytes[header + 8..header + 12].copy_from_slice(&0x0000332eu32.to_le_bytes());
bytes[header + 12..header + 16].copy_from_slice(&1u32.to_le_bytes());
bytes[header + 16..header + 20].copy_from_slice(&0x22u32.to_le_bytes());
bytes[header + 20..header + 24].copy_from_slice(&2u32.to_le_bytes());
bytes[header + 24..header + 28].copy_from_slice(&2u32.to_le_bytes());
bytes[header + 0x1c..header + 0x20].copy_from_slice(&0x44u32.to_le_bytes());
bytes[header + 0x20..header + 0x24]
.copy_from_slice(&(observed_entry_count as u32).to_le_bytes());
bytes[header + 0x28..header + 0x2c].copy_from_slice(&1u32.to_le_bytes());
for index in 0..observed_entry_count {
let name = match index {
0 => "AutoPlant".to_string(),
1 => "Nuclear Power Plant".to_string(),
66 => "Warehouse11".to_string(),
_ => format!("Entry{index:02}"),
};
let off = entries + index * stride;
let raw = &mut bytes[off..off + stride];
raw[..name.len()].copy_from_slice(name.as_bytes());
let trailer = if name == "Nuclear Power Plant" {
0u32
} else {
1u32
};
raw[stride - 4..stride].copy_from_slice(&trailer.to_le_bytes());
}
let footer = entries + observed_entry_count * stride;
bytes[footer..footer + 4].copy_from_slice(&0x32dcu32.to_le_bytes());
bytes[footer + 4..footer + 8].copy_from_slice(&0x3714u32.to_le_bytes());
bytes[footer + 8] = 0x00;
let probe = parse_rt3_105_save_name_table_probe(
&bytes,
Some("gmp"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-map-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
None,
)
.expect("map name table probe should parse");
assert_eq!(probe.profile_family, "rt3-105-map-container-v1");
assert_eq!(probe.source_kind, "map-fixed-catalog-range");
assert_eq!(probe.header_offset, header);
assert_eq!(probe.entries_offset, entries);
assert_eq!(probe.observed_entry_count, observed_entry_count);
assert_eq!(probe.entries[0].text, "AutoPlant");
assert_eq!(probe.entries[66].text, "Warehouse11");
assert_eq!(
probe.zero_trailer_entry_names,
vec!["Nuclear Power Plant".to_string()]
);
assert_eq!(probe.footer_progress_word_0, 0x32dc);
assert_eq!(probe.footer_progress_word_1, 0x3714);
}
#[test]
fn parses_rt3_105_save_named_locomotive_availability_probe() {
let mut bytes = vec![0u8; 0x9000];
let packed_profile_offset = 0x73c0usize;
let packed_profile_len = 0x108usize;
let entries_offset = 0x7c78usize;
let names = [
("Eight Wheeler 4-4-0", 1u32),
("EP-2 Bipolar", 1u32),
("ET22", 1u32),
("F3", 0u32),
("Fairlie 0-6-6-0", 1u32),
("Firefly 2-2-2", 0u32),
("FP45", 0u32),
("Ge 6/6 Crocodile", 1u32),
("GG1", 0u32),
("GP7", 1u32),
];
for (index, (name, value)) in names.iter().enumerate() {
let offset = entries_offset + index * RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE;
bytes[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
bytes[offset + 4..offset + 4 + name.len()].copy_from_slice(name.as_bytes());
}
let probe = parse_rt3_105_save_named_locomotive_availability_probe(
&bytes,
Some("gms"),
Some(&SmpContainerProfile {
profile_family: "rt3-105-save-container-v1".to_string(),
profile_evidence: vec![],
is_known_profile: true,
}),
Some(&SmpRt3105PackedProfileProbe {
profile_family: "rt3-105-save-container-v1".to_string(),
packed_profile_offset,
packed_profile_len,
packed_profile_len_hex: "0x108".to_string(),
packed_profile_block: SmpRt3105PackedProfileBlock {
relative_len: packed_profile_len,
relative_len_hex: "0x108".to_string(),
leading_word_0: 3,
leading_word_0_hex: "0x00000003".to_string(),
trailing_zero_word_count_after_leading_word: 2,
header_flag_word_3: 1,
header_flag_word_3_hex: "0x00000001".to_string(),
map_path_offset: 0x10,
map_path: Some("Alternate USA.gmp".to_string()),
display_name_offset: 0x43,
display_name: Some("Alternate USA".to_string()),
profile_byte_0x77: 0x07,
profile_byte_0x77_hex: "0x07".to_string(),
profile_byte_0x82: 0x4d,
profile_byte_0x82_hex: "0x4d".to_string(),
profile_byte_0x97: 0,
profile_byte_0x97_hex: "0x00".to_string(),
profile_byte_0xc5: 0,
profile_byte_0xc5_hex: "0x00".to_string(),
stable_nonzero_words: vec![],
},
ascii_runs: vec![],
}),
)
.expect("save-side locomotive table probe should parse");
assert_eq!(probe.source_kind, "save-direct-locomotive-row-run");
assert_eq!(
probe.semantic_family,
"scenario-named-locomotive-availability-table"
);
assert_eq!(probe.entries_offset, entries_offset);
assert_eq!(
probe.entry_stride,
RT3_105_SAVE_NAMED_LOCOMOTIVE_ENTRY_STRIDE
);
assert_eq!(probe.observed_entry_count, names.len());
assert_eq!(probe.zero_availability_count, 4);
assert_eq!(probe.entries[0].text, "Eight Wheeler 4-4-0");
assert_eq!(probe.entries[9].text, "GP7");
}
#[test]
fn classifies_rt3_105_alt_save_container_profile() {
let shared_header = SmpSharedHeader {
byte_len: 64,
root_kind_word: 0x000025e5,
root_kind_word_hex: "0x000025e5".to_string(),
primary_family_tag: 0x00002ee0,
primary_family_tag_hex: "0x00002ee0".to_string(),
shared_signature_words_1_to_7: vec![
0x00002ee0, 0x0001c001, 0x00018000, 0x00010000, 0x00000754, 0x00000754, 0x00000754,
],
shared_signature_hex_words_1_to_7: vec![
"0x00002ee0".to_string(),
"0x0001c001".to_string(),
"0x00018000".to_string(),
"0x00010000".to_string(),
"0x00000754".to_string(),
"0x00000754".to_string(),
"0x00000754".to_string(),
],
matches_grounded_common_signature: false,
payload_window_words_8_to_9: vec![0x007a5978, 0x007a9022],
payload_window_hex_words_8_to_9: vec![
"0x007a5978".to_string(),
"0x007a9022".to_string(),
],
reserved_words_10_to_14: vec![0; 5],
reserved_words_10_to_14_all_zero: true,
final_flag_word: 0,
final_flag_word_hex: "0x00000000".to_string(),
};
let early_content_probe = SmpEarlyContentProbe {
first_post_text_nonzero_offset: 722,
zero_pad_after_text_len: 431,
first_post_text_block_len: 35,
first_post_text_block_hex:
"0101010000010000000000000100000000000000010000000000000000010100000001".to_string(),
trailing_zero_pad_after_first_block_len: 45,
secondary_nonzero_offset: Some(802),
secondary_aligned_word_window_offset: Some(800),
secondary_aligned_word_window_words: vec![
0x00010000, 0x49f00100, 0x00000002, 0xa0000000, 0x00000186, 0x00000000, 0x000186a0,
0x00000000,
],
secondary_aligned_word_window_hex_words: vec![
"0x00010000".to_string(),
"0x49f00100".to_string(),
"0x00000002".to_string(),
"0xa0000000".to_string(),
"0x00000186".to_string(),
"0x00000000".to_string(),
"0x000186a0".to_string(),
"0x00000000".to_string(),
],
secondary_preview_hex:
"01000001f04902000000000000a08601000000000000a08601000000000000a0".to_string(),
};
let header_variant = classify_header_variant_probe(&shared_header);
let secondary_variant =
classify_secondary_variant_probe(&early_content_probe).expect("secondary probe");
let container_profile = classify_container_profile(
Some("gms"),
Some(&header_variant),
Some(&secondary_variant),
)
.expect("container profile");
assert_eq!(header_variant.variant_family, "rt3-105-alt-save-header-v1");
assert_eq!(
secondary_variant.variant_family,
"rt3-105-gms-alt-family-v1"
);
assert_eq!(
container_profile.profile_family,
"rt3-105-alt-save-container-v1"
);
assert!(container_profile.is_known_profile);
}
#[test]
fn classifies_rt3_105_map_container_profiles_from_header_families() {
let scenario_profile = classify_container_profile(
Some("gmp"),
Some(&SmpHeaderVariantProbe {
variant_family: "rt3-105-scenario-save-header-v1".to_string(),
variant_evidence: vec![],
is_known_family: true,
}),
Some(&SmpSecondaryVariantProbe {
aligned_window_offset: 0,
words: vec![1, 0, 0, 0],
hex_words: vec![],
variant_family: "unknown".to_string(),
variant_evidence: vec![],
}),
)
.expect("scenario map profile");
let alt_profile = classify_container_profile(
Some("gmp"),
Some(&SmpHeaderVariantProbe {
variant_family: "rt3-105-alt-save-header-v1".to_string(),
variant_evidence: vec![],
is_known_family: true,
}),
Some(&SmpSecondaryVariantProbe {
aligned_window_offset: 0,
words: vec![0x49f00100, 2, 0xa0000000, 0x186],
hex_words: vec![],
variant_family: "unknown".to_string(),
variant_evidence: vec![],
}),
)
.expect("alt map profile");
assert_eq!(
scenario_profile.profile_family,
"rt3-105-scenario-map-container-v1"
);
assert!(scenario_profile.is_known_profile);
assert_eq!(alt_profile.profile_family, "rt3-105-alt-map-container-v1");
assert!(alt_profile.is_known_profile);
}
fn empty_analysis_report() -> SmpSaveCompanyChairmanAnalysisReport {
SmpSaveCompanyChairmanAnalysisReport {
profile_family: "rt3-105-scenario-save-container-v1".to_string(),
selected_company_id: None,
selected_chairman_profile_id: None,
world_selection_context: None,
world_issue_37: None,
world_economic_tuning: None,
world_finance_neighborhood: None,
train_collection_header: None,
train_collection_directory: None,
region_collection_header: None,
region_record_triplets: None,
region_queued_notice_records: None,
region_fixed_row_run_candidates: None,
placed_structure_collection_header: None,
placed_structure_record_triplets: None,
placed_structure_dynamic_side_buffer: None,
placed_structure_dynamic_side_buffer_alignment: None,
unclassified_tagged_collection_headers: Vec::new(),
company_entries: Vec::new(),
chairman_entries: Vec::new(),
notes: Vec::new(),
}
}
#[test]
fn compares_region_fixed_row_run_candidates_by_shape_signature() {
let mut left = empty_analysis_report();
left.region_fixed_row_run_candidates = Some(SmpSaveRegionFixedRowRunCandidateProbe {
profile_family: left.profile_family.clone(),
source_kind: "save-region-fixed-row-run-candidates".to_string(),
semantic_family: "scenario-save-region-fixed-row-run-candidates".to_string(),
target_row_count: 145,
target_row_stride: 0x29,
target_row_stride_hex: "0x29".to_string(),
scan_start_offset: 0,
scan_start_offset_hex: "0x0".to_string(),
scan_end_offset: 0x100,
scan_end_offset_hex: "0x100".to_string(),
candidates: vec![
SmpSaveRegionFixedRowRunCandidate {
count_offset: 0x20,
count_offset_hex: "0x20".to_string(),
row_count: 145,
row_stride: 0x29,
row_stride_hex: "0x29".to_string(),
rows_offset: 0x24,
rows_offset_hex: "0x24".to_string(),
rows_end_offset: 0x39,
rows_end_offset_hex: "0x39".to_string(),
distance_to_region_metadata_tag: 0xc7,
distance_to_region_metadata_tag_hex: "0xc7".to_string(),
dword_lane_summaries: Vec::new(),
shape_signature: "pf32=[0x14:120]|small=[0x20:17]|zero=[0x20:11]|trail=28/63"
.to_string(),
shape_family_signature:
"dense_pf32=[0x14]|small_nonzero=[0x20]|partial_zero=[0x20]|trail_bucket=3/7"
.to_string(),
trailing_byte_zero_count: 28,
trailing_byte_nonzero_count: 117,
trailing_byte_distinct_value_count: 63,
trailing_byte_sample_values_hex: Vec::new(),
best_probable_density_lane_relative_offset_hex: Some("0x14".to_string()),
},
SmpSaveRegionFixedRowRunCandidate {
count_offset: 0x40,
count_offset_hex: "0x40".to_string(),
row_count: 145,
row_stride: 0x29,
row_stride_hex: "0x29".to_string(),
rows_offset: 0x44,
rows_offset_hex: "0x44".to_string(),
rows_end_offset: 0x59,
rows_end_offset_hex: "0x59".to_string(),
distance_to_region_metadata_tag: 0xa7,
distance_to_region_metadata_tag_hex: "0xa7".to_string(),
dword_lane_summaries: Vec::new(),
shape_signature: "pf32=[0x18:107]|small=[0x10:17]|zero=[0x14:12]|trail=32/58"
.to_string(),
shape_family_signature:
"dense_pf32=[]|small_nonzero=[0x10]|partial_zero=[0x14]|trail_bucket=4/7"
.to_string(),
trailing_byte_zero_count: 32,
trailing_byte_nonzero_count: 113,
trailing_byte_distinct_value_count: 58,
trailing_byte_sample_values_hex: Vec::new(),
best_probable_density_lane_relative_offset_hex: Some("0x18".to_string()),
},
],
evidence: Vec::new(),
});
let mut right = empty_analysis_report();
right.region_fixed_row_run_candidates = Some(SmpSaveRegionFixedRowRunCandidateProbe {
profile_family: right.profile_family.clone(),
source_kind: "save-region-fixed-row-run-candidates".to_string(),
semantic_family: "scenario-save-region-fixed-row-run-candidates".to_string(),
target_row_count: 145,
target_row_stride: 0x29,
target_row_stride_hex: "0x29".to_string(),
scan_start_offset: 0,
scan_start_offset_hex: "0x0".to_string(),
scan_end_offset: 0x100,
scan_end_offset_hex: "0x100".to_string(),
candidates: vec![
SmpSaveRegionFixedRowRunCandidate {
count_offset: 0x80,
count_offset_hex: "0x80".to_string(),
row_count: 145,
row_stride: 0x29,
row_stride_hex: "0x29".to_string(),
rows_offset: 0x84,
rows_offset_hex: "0x84".to_string(),
rows_end_offset: 0x99,
rows_end_offset_hex: "0x99".to_string(),
distance_to_region_metadata_tag: 0x67,
distance_to_region_metadata_tag_hex: "0x67".to_string(),
dword_lane_summaries: Vec::new(),
shape_signature: "pf32=[0x18:107]|small=[0x10:17]|zero=[0x14:12]|trail=32/58"
.to_string(),
shape_family_signature:
"dense_pf32=[]|small_nonzero=[0x10]|partial_zero=[0x14]|trail_bucket=4/7"
.to_string(),
trailing_byte_zero_count: 32,
trailing_byte_nonzero_count: 113,
trailing_byte_distinct_value_count: 58,
trailing_byte_sample_values_hex: Vec::new(),
best_probable_density_lane_relative_offset_hex: Some("0x18".to_string()),
},
SmpSaveRegionFixedRowRunCandidate {
count_offset: 0xa0,
count_offset_hex: "0xa0".to_string(),
row_count: 145,
row_stride: 0x29,
row_stride_hex: "0x29".to_string(),
rows_offset: 0xa4,
rows_offset_hex: "0xa4".to_string(),
rows_end_offset: 0xb9,
rows_end_offset_hex: "0xb9".to_string(),
distance_to_region_metadata_tag: 0x47,
distance_to_region_metadata_tag_hex: "0x47".to_string(),
dword_lane_summaries: Vec::new(),
shape_signature: "pf32=[0x24:100]|small=[0xc:16]|zero=[0xc:11]|trail=34/60"
.to_string(),
shape_family_signature:
"dense_pf32=[]|small_nonzero=[0xc]|partial_zero=[0xc]|trail_bucket=4/7"
.to_string(),
trailing_byte_zero_count: 34,
trailing_byte_nonzero_count: 111,
trailing_byte_distinct_value_count: 60,
trailing_byte_sample_values_hex: Vec::new(),
best_probable_density_lane_relative_offset_hex: Some("0x24".to_string()),
},
],
evidence: Vec::new(),
});
let comparison = compare_save_region_fixed_row_run_candidates(&left, &right)
.expect("comparison should build");
assert_eq!(comparison.shared_shape_matches.len(), 1);
assert_eq!(
comparison.shared_shape_matches[0].shape_signature,
"pf32=[0x18:107]|small=[0x10:17]|zero=[0x14:12]|trail=32/58"
);
assert_eq!(comparison.shared_shape_matches[0].left_rank, 2);
assert_eq!(comparison.shared_shape_matches[0].right_rank, 1);
assert_eq!(comparison.shared_shape_family_matches.len(), 1);
assert_eq!(
comparison.shared_shape_family_matches[0].shape_signature,
"dense_pf32=[]|small_nonzero=[0x10]|partial_zero=[0x14]|trail_bucket=4/7"
);
assert_eq!(comparison.left_only_shape_signatures.len(), 1);
assert_eq!(comparison.right_only_shape_signatures.len(), 1);
}
#[test]
fn builds_region_service_trace_report_with_explicit_latch_blockers() {
let mut analysis = empty_analysis_report();
analysis.region_record_triplets = Some(SmpSaveRegionRecordTripletProbe {
profile_family: analysis.profile_family.clone(),
source_kind: "save-region-record-triplets".to_string(),
semantic_family: "marker09".to_string(),
records_tag_offset: 0,
close_tag_offset: 0,
record_count: 1,
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: 0,
profile_tag_relative_offset: 0,
pre_name_prefix_len: 0,
pre_name_prefix_hex_bytes: Vec::new(),
pre_name_prefix_dword_candidates: Vec::new(),
policy_chunk_len: 0,
profile_chunk_len: 0,
policy_leading_f32_0: 368.0,
policy_leading_f32_1: 0.0,
policy_leading_f32_2: 92.0,
policy_reserved_dwords: Vec::new(),
policy_reserved_dword_candidates: Vec::new(),
policy_trailing_word: 0,
policy_trailing_word_hex: "0x0000".to_string(),
profile_collection: Some(SmpSaveRegionProfileCollectionProbe {
direct_collection_flag: 1,
entry_stride: 0x22,
live_id_bound: 17,
live_record_count: 17,
entry_start_relative_offset: 0,
trailing_padding_len: 0,
entries: Vec::new(),
}),
}],
evidence: Vec::new(),
});
let trace = build_region_service_trace_report(&analysis);
assert_eq!(trace.region_record_triplet_count, 1);
assert_eq!(trace.queued_notice_record_count, 0);
assert!(!trace.atlas_candidate_consumers.is_empty());
assert_eq!(trace.known_owner_bridge_fields.len(), 6);
assert_eq!(trace.known_bridge_helpers.len(), 14);
assert_eq!(trace.next_owner_questions.len(), 3);
assert_eq!(trace.candidate_consumer_hypotheses.len(), 4);
assert_eq!(
trace.candidate_consumer_hypotheses[0].status,
"highest_priority_static_mapping_target"
);
assert_eq!(
trace.candidate_consumer_hypotheses[2].status,
"secondary_candidate_after_pending_service"
);
assert_eq!(
trace.candidate_consumer_hypotheses[1].status,
"parallel_static_mapping_target"
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x5209")
&& line.contains("0x520a")
&& line.contains("0x520b"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x0041f5c0")
&& line.contains("[region+0x37f]")
&& line.contains("[region+0x385]"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x00444887")
&& line.contains("0x00487c20")
&& line.contains("0x0040b5d0"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x00421ce0") && line.contains("0x0041fb00"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x00421730")
&& line.contains("[region+0x242/+0x246/+0x24a/+0x24e/+0x252]"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x00448740..0x0044881f")
&& line.contains("0x006cfc9c")
&& line.contains("0x53b070")
&& line.contains("0x00487bd0"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x00487de0")
&& line.contains("0x00533cf0")
&& line.contains("0x00536ea0"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x0044c4b0")
&& line.contains("0x00455f60")
&& line.contains("bit 0x10"))
);
assert!(
trace.candidate_consumer_hypotheses[1]
.evidence
.iter()
.any(|line| line.contains("0x004881b0")
&& line.contains("[region+0x3d]")
&& line.contains("[region+0x41]"))
);
assert_eq!(trace.entries.len(), 1);
assert_eq!(
trace.entries[0].branches[0].status,
"blocked_missing_pending_bonus_owner_lane"
);
assert_eq!(
trace.entries[0].branches[1].status,
"blocked_missing_completion_and_one_shot_latches"
);
assert!(
trace
.notes
.iter()
.any(|line| { line.contains("pre-name prefix lengths") && line.contains("[0]") })
);
}
#[test]
fn builds_periodic_company_service_trace_report_with_candidate_consumers() {
let mut analysis = empty_analysis_report();
analysis.selected_company_id = Some(7);
analysis
.company_entries
.push(SmpSaveCompanyRecordAnalysisEntry {
company_id: 7,
name: "Test Company".to_string(),
active: true,
linked_chairman_profile_id: Some(3),
outstanding_shares: 1000,
debt: 0,
bond_count: 0,
live_bond_slots: Vec::new(),
largest_live_bond_principal: None,
highest_coupon_live_bond_principal: None,
available_track_laying_capacity: Some(5),
company_value_scalar_f32: 1.0,
cached_share_support_scalar_f32: 1.0,
cached_share_price_f32: 1.0,
chairman_salary_baseline: 0,
chairman_salary_current: 0,
chairman_bonus_year: 0,
chairman_bonus_amount: 0,
founding_year: 1900,
last_bankruptcy_year: 0,
last_dividend_year: 0,
preferred_locomotive_engine_type_raw_u8: 2,
preferred_locomotive_engine_type_raw_hex: "0x02".to_string(),
city_connection_latch: true,
linked_transit_latch: false,
merger_cooldown_year: 0,
takeover_cooldown_year: 0,
scalar_dword_candidates: Vec::new(),
post_capacity_dword_candidates: Vec::new(),
stat_band_root_0cfb_candidates: Vec::new(),
stat_band_root_0d7f_candidates: Vec::new(),
stat_band_root_1c47_candidates: Vec::new(),
});
let trace = build_periodic_company_service_trace_report(&analysis);
assert_eq!(trace.selected_company_id, Some(7));
assert_eq!(trace.atlas_candidate_consumers.len(), 7);
assert_eq!(trace.known_bridge_helpers.len(), 38);
assert_eq!(trace.next_owner_questions.len(), 4);
assert_eq!(trace.companies.len(), 1);
assert_eq!(
trace.peer_site_selector_candidate_owner_strip,
"0x0045c150 -> 0x0045c310 -> 0x0045c36e -> 0x00456100 -> 0x00455b70"
);
assert_eq!(
trace.peer_site_selector_candidate_persisted_tag_hex,
"0x5dc1"
);
assert_eq!(
trace.peer_site_selector_candidate_selector_lane,
"[owner+0x23e]"
);
assert_eq!(
trace.peer_site_selector_candidate_class_identity_status,
"grounded_direct_local_helper_strip"
);
assert_eq!(trace.peer_site_selector_candidate_helper_linkage.len(), 4);
assert_eq!(trace.peer_site_restore_input_fields.len(), 4);
assert_eq!(trace.peer_site_runtime_input_fields.len(), 3);
assert_eq!(
trace.peer_site_runtime_reconstruction_status,
"restore_subset_and_bring_up_reconstruct_runtime_subset"
);
assert_eq!(trace.peer_site_runtime_reconstruction_steps.len(), 3);
assert_eq!(trace.near_city_acquisition_region_input_fields.len(), 5);
assert_eq!(trace.near_city_acquisition_peer_input_fields.len(), 5);
assert_eq!(trace.near_city_acquisition_company_input_fields.len(), 4);
assert_eq!(
trace.near_city_acquisition_shellless_readiness_status,
"peer_and_company_inputs_grounded_region_restore_gap_remaining"
);
assert_eq!(
trace
.near_city_acquisition_runtime_backed_input_families
.len(),
5
);
assert_eq!(trace.near_city_acquisition_remaining_owner_gaps.len(), 4);
assert_eq!(trace.near_city_acquisition_region_lane_statuses.len(), 4);
assert!(trace.atlas_candidate_consumers.iter().any(|line| {
line.contains("0x00420030 / 0x00420280")
&& line.contains("0x006cec20")
&& line.contains("peer-site boolean/selector pair")
}));
assert!(trace.next_owner_questions.iter().any(|line| {
line.contains("remaining region-side 0x004014b0 inputs")
&& line.contains("0x004014b0")
&& line.contains("[region+0x2a4]")
}));
assert!(
trace
.near_city_acquisition_region_input_fields
.iter()
.any(|line| line.contains("[region+0x276]"))
);
assert!(
trace
.near_city_acquisition_peer_input_fields
.iter()
.any(|line| line.contains("[site+0x04]"))
);
assert!(
trace
.near_city_acquisition_company_input_fields
.iter()
.any(|line| line.contains("0x2329/0x0d"))
);
assert!(
trace
.near_city_acquisition_runtime_backed_input_families
.iter()
.any(|line| line.contains("0x2329/0x0d"))
);
assert!(
trace
.near_city_acquisition_remaining_owner_gaps
.iter()
.any(|line| line.contains("[region+0x276]"))
);
assert!(
trace
.near_city_acquisition_region_lane_statuses
.iter()
.any(|line| line.contains("[region+0x2a4]")
&& line.contains("no region-class runtime writer"))
);
assert!(trace.next_owner_questions.iter().any(|line| {
line.contains("0x004160aa")
&& line.contains("0x0040ee10")
&& line.contains("0x0040edf6")
}));
let acquisition_branch = trace.companies[0]
.branches
.iter()
.find(|branch| branch.branch_name == "industry_acquisition_side_branch")
.expect("missing acquisition branch");
assert_eq!(
acquisition_branch.status,
"blocked_missing_near-city_owner_mapping"
);
assert!(
acquisition_branch
.candidate_consumers
.iter()
.any(|line| line.contains("0x004014b0"))
);
assert!(
acquisition_branch
.candidate_consumers
.iter()
.any(|line| line.contains("0x004019e0"))
);
assert!(
acquisition_branch
.candidate_consumers
.iter()
.any(|line| line.contains("0x004010f0"))
);
assert!(
acquisition_branch
.candidate_consumers
.iter()
.any(|line| line.contains("0x00420030 / 0x00420280"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00405920"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x0041f6e0") && line.contains("0x0042b2d0"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00480710") && line.contains("route-entry-anchor"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x0040f6d0") && line.contains("0x00481390"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x0040df27 / 0x0040e00a / 0x0040edf6"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00444690") && line.contains("0x004133b0"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x0040e450") && line.contains("queued site-id"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x004160aa") && line.contains("0x0040ee10"))
);
let city_branch = trace.companies[0]
.branches
.iter()
.find(|branch| branch.branch_name == "city_connection_announcement")
.expect("missing city branch");
assert!(
city_branch
.candidate_consumers
.iter()
.any(|line| line.contains("0x00406050"))
);
}
#[test]
fn builds_infrastructure_asset_trace_report_with_alias_disproved_status() {
let mut analysis = empty_analysis_report();
analysis.placed_structure_record_triplets =
Some(SmpSavePlacedStructureRecordTripletProbe {
profile_family: analysis.profile_family.clone(),
source_kind: "save-placed-structure-triplets".to_string(),
semantic_family: "placed-structure-triplets".to_string(),
records_tag_offset: 0,
close_tag_offset: 0,
record_count: 2057,
entries: Vec::new(),
evidence: Vec::new(),
});
analysis.placed_structure_dynamic_side_buffer =
Some(SmpSavePlacedStructureDynamicSideBufferProbe {
profile_family: analysis.profile_family.clone(),
source_kind: "save-side-buffer".to_string(),
semantic_family: "infrastructure-asset".to_string(),
metadata_tag_offset: 0,
records_tag_offset: 0,
close_tag_offset: 0,
records_span_len: 0,
direct_record_stride: 6,
direct_record_stride_hex: "0x00000006".to_string(),
live_id_bound: 3865,
live_id_bound_hex: "0x00000f19".to_string(),
live_record_count: 3865,
live_record_count_hex: "0x00000f19".to_string(),
owner_shared_dword: 0xff000000,
owner_shared_dword_hex: "0xff000000".to_string(),
owner_shared_dword_relative_offset: 0,
owner_shared_dword_matches_first_compact_prefix_leading_dword: true,
first_record_child_count_after_owner_shared: Some(1),
first_record_child_count_after_owner_shared_hex: Some("0x0001".to_string()),
first_record_saved_primary_child_byte_after_owner_shared: Some(0xff),
first_record_saved_primary_child_byte_after_owner_shared_hex: Some(
"0xff".to_string(),
),
first_record_first_name_tag_relative_offset_after_owner_shared: Some(3),
prefix_leading_dword: 0xff000000,
prefix_leading_dword_hex: "0xff000000".to_string(),
prefix_trailing_word: 1,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
first_embedded_name_tag_relative_offset: 0x20,
embedded_name_tag_count: 138,
decoded_embedded_name_row_count: 138,
decoded_embedded_name_row_with_tertiary_name_count: 0,
unique_compact_prefix_pattern_count: 7,
prefix_leading_dword_matching_embedded_profile_tag_count: 17,
unique_embedded_name_pair_count: 5,
first_embedded_primary_name: Some("TrackCapST_Cap.3dp".to_string()),
first_embedded_secondary_name: Some("Infrastructure".to_string()),
first_embedded_tertiary_name: None,
embedded_name_row_samples: Vec::new(),
compact_prefix_pattern_summaries: Vec::new(),
name_pair_summaries: vec![SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
primary_name: "TrackCapST_Cap.3dp".to_string(),
secondary_name: "Infrastructure".to_string(),
count: 12,
first_name_tag_relative_offset: 0x20,
unique_compact_prefix_pattern_count: 2,
dominant_prefix_leading_dword: 0xff0000ff,
dominant_prefix_leading_dword_hex: "0xff0000ff".to_string(),
dominant_prefix_trailing_word: 1,
dominant_prefix_trailing_word_hex: "0x0001".to_string(),
dominant_prefix_separator_byte: 0xff,
dominant_prefix_separator_byte_hex: "0xff".to_string(),
dominant_prefix_count: 9,
}],
payload_envelope_summary: Some(
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
row_count_with_policy_tag_before_next_name: 120,
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope: 118,
row_count_missing_policy_tag_before_next_name: 18,
row_count_missing_profile_tag_after_policy: 2,
unique_policy_chunk_lens: vec![0x1a, 0x24],
unique_profile_chunk_lens: vec![0x08, 0x14],
dominant_policy_chunk_len: Some(0x1a),
dominant_policy_chunk_len_count: 110,
dominant_profile_chunk_len: Some(0x08),
dominant_profile_chunk_len_count: 90,
short_profile_flag_pair_summary: Some(
SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPairSummary {
row_count_with_0x06_profile_span: 72,
unique_flag_pair_count: 2,
dominant_first_flag_byte: Some(0x01),
dominant_first_flag_byte_hex: Some("0x01".to_string()),
dominant_first_flag_byte_count: 60,
dominant_second_flag_byte: Some(0x00),
dominant_second_flag_byte_hex: Some("0x00".to_string()),
dominant_second_flag_byte_count: 55,
dominant_flag_pair: Some(
SmpSavePlacedStructureDynamicSideBufferShortProfileFlagPair {
first_flag_byte: 0x01,
first_flag_byte_hex: "0x01".to_string(),
second_flag_byte: 0x00,
second_flag_byte_hex: "0x00".to_string(),
count: 48,
},
),
sample_rows: Vec::new(),
},
),
fixed_policy_summary: Some(
SmpSavePlacedStructureDynamicSideBufferFixedPolicySummary {
row_count_with_0x1a_policy_chunk: 118,
unique_trailing_word_count: 1,
dominant_trailing_word: Some(1),
dominant_trailing_word_hex: Some("0x0001".to_string()),
dominant_trailing_word_count: 118,
compact_prefix_correlations: Vec::new(),
sample_rows: Vec::new(),
},
),
name_prelude_candidate_summary: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidateSummary {
row_count_with_candidate_window: 118,
unique_candidate_pattern_count: 2,
dominant_child_count_candidate: Some(1),
dominant_child_count_candidate_count: 110,
dominant_saved_primary_child_byte_candidate: Some(0xff),
dominant_saved_primary_child_byte_candidate_hex: Some(
"0xff".to_string(),
),
dominant_saved_primary_child_byte_candidate_count: 110,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
count: 110,
},
),
candidate_pattern_correlations: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePatternCorrelation {
child_count_candidate: 2,
child_count_candidate_hex: "0x0002".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
row_count: 18,
unique_name_pair_count: 1,
unique_profile_span_count: 1,
dominant_primary_name: Some(
"BridgeSTWood_Section.3dp".to_string(),
),
dominant_secondary_name: Some(
"Infrastructure".to_string(),
),
dominant_name_pair_count: 18,
dominant_profile_span: Some(6),
dominant_profile_span_count: 10,
dominant_mode_family: Some("bridge".to_string()),
dominant_mode_family_count: 18,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "bridge".to_string(),
count: 18,
},
],
sample_rows: Vec::new(),
},
],
profile_span_correlations: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
previous_profile_chunk_len_to_next_name_or_end: 3,
row_count: 17,
dominant_child_count_candidate: Some(1),
dominant_child_count_candidate_count: 17,
dominant_saved_primary_child_byte_candidate: Some(0xff),
dominant_saved_primary_child_byte_candidate_hex: Some(
"0xff".to_string(),
),
dominant_saved_primary_child_byte_candidate_count: 17,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff"
.to_string(),
count: 17,
},
),
dominant_mode_family: Some("tunnel".to_string()),
dominant_mode_family_count: 15,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "track_cap".to_string(),
count: 2,
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "tunnel".to_string(),
count: 15,
},
],
compact_prefix_pattern_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
prefix_leading_dword: 0x0000_55f3,
prefix_leading_dword_hex: "0x000055f3".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
count: 17,
},
],
sample_rows: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
sample_index: 0,
name_tag_relative_offset: 1200,
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
prefix_leading_dword: 0x0000_55f3,
prefix_leading_dword_hex: "0x000055f3".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
},
],
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
previous_profile_chunk_len_to_next_name_or_end: 6,
row_count: 72,
dominant_child_count_candidate: Some(1),
dominant_child_count_candidate_count: 62,
dominant_saved_primary_child_byte_candidate: Some(0xff),
dominant_saved_primary_child_byte_candidate_hex: Some(
"0xff".to_string(),
),
dominant_saved_primary_child_byte_candidate_count: 72,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff"
.to_string(),
count: 62,
},
),
dominant_mode_family: Some("bridge".to_string()),
dominant_mode_family_count: 72,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "bridge".to_string(),
count: 72,
},
],
compact_prefix_pattern_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
prefix_leading_dword: 0xff00_0000,
prefix_leading_dword_hex: "0xff000000".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
count: 72,
},
],
sample_rows: vec![],
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanCorrelation {
previous_profile_chunk_len_to_next_name_or_end: 0x27,
row_count: 3,
dominant_child_count_candidate: Some(1),
dominant_child_count_candidate_count: 3,
dominant_saved_primary_child_byte_candidate: Some(0xff),
dominant_saved_primary_child_byte_candidate_hex: Some(
"0xff".to_string(),
),
dominant_saved_primary_child_byte_candidate_count: 3,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff"
.to_string(),
count: 3,
},
),
dominant_mode_family: Some("bridge".to_string()),
dominant_mode_family_count: 2,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "bridge".to_string(),
count: 2,
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "tunnel".to_string(),
count: 1,
},
],
compact_prefix_pattern_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
count: 1,
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanPrefixSummary {
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0002,
prefix_trailing_word_hex: "0x0002".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
count: 2,
},
],
sample_rows: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
sample_index: 0,
name_tag_relative_offset: 2805,
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeProfileSpanSample {
sample_index: 1,
name_tag_relative_offset: 3764,
primary_name: Some("BridgeSTWood_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0002,
prefix_trailing_word_hex: "0x0002".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
},
],
},
],
compact_prefix_correlations: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation {
prefix_leading_dword: 0x0000_55f3,
prefix_leading_dword_hex: "0x000055f3".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
row_count: 17,
unique_name_pair_count: 2,
unique_profile_span_count: 1,
dominant_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
dominant_secondary_name: Some("Infrastructure".to_string()),
dominant_name_pair_count: 15,
dominant_profile_span: Some(3),
dominant_profile_span_count: 17,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
count: 17,
},
),
dominant_mode_family: Some("tunnel".to_string()),
dominant_mode_family_count: 15,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "track_cap".to_string(),
count: 2,
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "tunnel".to_string(),
count: 15,
},
],
name_pair_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
count: 15,
},
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name: Some("TrackCapST_Cap.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
count: 2,
},
],
profile_span_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount {
previous_profile_chunk_len_to_next_name_or_end: 3,
count: 17,
},
],
rows_with_previous_short_profile_flag_pair: 17,
previous_short_profile_flag_pair_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount {
first_flag_byte: 0x00,
first_flag_byte_hex: "0x00".to_string(),
second_flag_byte: 0x01,
second_flag_byte_hex: "0x01".to_string(),
count: 17,
},
],
sample_rows: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample {
sample_index: 0,
name_tag_relative_offset: 1200,
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
previous_profile_chunk_len_to_next_name_or_end: Some(3),
},
],
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation {
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0001,
prefix_trailing_word_hex: "0x0001".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
row_count: 1,
unique_name_pair_count: 1,
unique_profile_span_count: 1,
dominant_primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
dominant_secondary_name: Some("Infrastructure".to_string()),
dominant_name_pair_count: 1,
dominant_profile_span: Some(0x27),
dominant_profile_span_count: 1,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
count: 1,
},
),
dominant_mode_family: Some("tunnel".to_string()),
dominant_mode_family_count: 1,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "tunnel".to_string(),
count: 1,
},
],
name_pair_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
count: 1,
},
],
profile_span_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount {
previous_profile_chunk_len_to_next_name_or_end: 0x27,
count: 1,
},
],
rows_with_previous_short_profile_flag_pair: 1,
previous_short_profile_flag_pair_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount {
first_flag_byte: 0x00,
first_flag_byte_hex: "0x00".to_string(),
second_flag_byte: 0x01,
second_flag_byte_hex: "0x01".to_string(),
count: 1,
},
],
sample_rows: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample {
sample_index: 0,
name_tag_relative_offset: 2805,
primary_name: Some("TunnelSTBrick_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
previous_profile_chunk_len_to_next_name_or_end: Some(0x27),
},
],
},
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixCorrelation {
prefix_leading_dword: 0xff00_00ff,
prefix_leading_dword_hex: "0xff0000ff".to_string(),
prefix_trailing_word: 0x0002,
prefix_trailing_word_hex: "0x0002".to_string(),
prefix_separator_byte: 0xff,
prefix_separator_byte_hex: "0xff".to_string(),
row_count: 2,
unique_name_pair_count: 1,
unique_profile_span_count: 1,
dominant_primary_name: Some("BridgeSTWood_Section.3dp".to_string()),
dominant_secondary_name: Some("Infrastructure".to_string()),
dominant_name_pair_count: 2,
dominant_profile_span: Some(0x27),
dominant_profile_span_count: 2,
dominant_candidate_pattern: Some(
SmpSavePlacedStructureDynamicSideBufferNamePreludeCandidatePattern {
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
count: 2,
},
),
dominant_mode_family: Some("bridge".to_string()),
dominant_mode_family_count: 2,
mode_family_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeModeFamilyCount {
mode_family: "bridge".to_string(),
count: 2,
},
],
name_pair_summaries: vec![
SmpSavePlacedStructureDynamicSideBufferDominantProfileSpanNamePairSummary {
primary_name: Some("BridgeSTWood_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
count: 2,
},
],
profile_span_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixProfileSpanCount {
previous_profile_chunk_len_to_next_name_or_end: 0x27,
count: 2,
},
],
rows_with_previous_short_profile_flag_pair: 2,
previous_short_profile_flag_pair_counts: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixFlagPairCount {
first_flag_byte: 0x00,
first_flag_byte_hex: "0x00".to_string(),
second_flag_byte: 0x01,
second_flag_byte_hex: "0x01".to_string(),
count: 2,
},
],
sample_rows: vec![
SmpSavePlacedStructureDynamicSideBufferNamePreludeCompactPrefixSample {
sample_index: 0,
name_tag_relative_offset: 3764,
primary_name: Some("BridgeSTWood_Section.3dp".to_string()),
secondary_name: Some("Infrastructure".to_string()),
child_count_candidate: 1,
child_count_candidate_hex: "0x0001".to_string(),
saved_primary_child_byte_candidate: 0xff,
saved_primary_child_byte_candidate_hex: "0xff".to_string(),
previous_profile_chunk_len_to_next_name_or_end: Some(0x27),
},
],
},
],
sample_rows: Vec::new(),
},
),
dominant_profile_span_class_summary: None,
sample_rows: Vec::new(),
},
),
live_entry_prelude_summary: Some(
SmpSavePlacedStructureDynamicSideBufferLiveEntryPreludeSummary {
live_entry_directory_row_count: 3865,
decoded_live_entry_id_count: 3865,
payload_relative_offset_monotonic: true,
rows_with_payload_pointer_inside_records_span: 138,
rows_with_zero_child_count: 0,
rows_with_nonzero_child_count: 138,
rows_with_first_name_tag_after_prelude: 138,
rows_with_first_name_tag_at_offset_3: 138,
unique_child_count_values: vec![1],
unique_first_name_tag_relative_offsets: vec![3],
dominant_child_count: Some(1),
dominant_child_count_count: 138,
dominant_saved_primary_child_byte: Some(0),
dominant_saved_primary_child_byte_hex: Some("0x00".to_string()),
dominant_saved_primary_child_byte_count: 138,
dominant_first_name_tag_relative_offset: Some(3),
dominant_first_name_tag_relative_offset_count: 138,
sample_rows: Vec::new(),
},
),
evidence: Vec::new(),
});
analysis.placed_structure_dynamic_side_buffer_alignment =
Some(SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
unique_side_buffer_name_pair_count: 5,
unique_triplet_name_pair_count: 56,
overlapping_name_pair_count: 0,
side_buffer_row_count: 138,
side_buffer_rows_with_matching_triplet_name_pair_count: 0,
side_buffer_rows_without_matching_triplet_name_pair_count: 138,
triplet_name_pairs_without_side_buffer_match_count: 56,
matched_name_pair_samples: Vec::new(),
unmatched_side_buffer_name_pair_samples: Vec::new(),
evidence: Vec::new(),
});
let trace = build_infrastructure_asset_trace_report(&analysis);
assert!(trace.side_buffer_present);
assert_eq!(trace.triplet_alignment_overlap_count, 0);
assert_eq!(trace.known_owner_bridge_fields.len(), 7);
assert_eq!(trace.known_bridge_helpers.len(), 21);
assert_eq!(trace.next_owner_questions.len(), 4);
assert!(trace.next_owner_questions.iter().any(|line| {
line.contains("compact-prefix regimes subdivide")
&& line.contains("0x0a BallastCap")
&& line.contains("0x0b TrackCap")
&& line.contains("0x02 Tunnel")
&& line.contains("0x01 Bridge")
}));
assert!(trace.next_owner_questions.iter().any(|line| {
line.contains("direct route-entry bridge helpers")
&& line.contains("0x00448a70/0x00493660/0x0048b660")
&& line.contains("[this+0x248]")
&& line.contains("cache/cleanup state")
}));
assert!(trace.known_bridge_helpers.iter().any(
|line| line.contains("0x004a2c80/0x004a34e0")
&& line.contains("paired upstream infrastructure composition choosers")
&& line.contains("BallastCap/Overpass")
));
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x0048a340")
&& line.contains("[0x226]/[0x219]/[0x251]/bit 0x20"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00455a40") && line.contains("slot +0x44"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x004559d0") && line.contains("0x55f1/0x55f2/0x55f3"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00490960") && line.contains("selector propagator"))
);
assert!(
trace
.known_bridge_helpers
.iter()
.any(|line| line.contains("0x00490200") && line.contains("route/link comparator"))
);
assert_eq!(trace.candidate_consumer_hypotheses.len(), 3);
assert_eq!(
trace.candidate_consumer_hypotheses[0].status,
"highest_priority_static_mapping_target"
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x004a2c80 routes the DT family")
&& line.contains("0x004a34e0 routes the ST family")
&& line.contains("0x0048a340/0x0048f4c0/0x00490200/0x00490960"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x621a44/0x621a54 feed BridgeST")
&& line.contains("0x621a94 feeds TunnelDT variants")
&& line.contains("BallastCapDT/ST")
&& line.contains("OverpassDT/ST"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("[this+0x226]==1 routes bridge families")
&& line.contains("[this+0x226]==2 routes tunnel families")
&& line.contains("[this+0x226]==3 routes overpass/ballast families")
&& line.contains("bit 0x20 in [this+0x24c]")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("0x0048a340 as the exact chooser-state setter")
&& line.contains("[this+0x226]")
&& line.contains("[this+0x219]")
&& line.contains("[this+0x251]")
&& line.contains("[this+0x24c]")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("[this+0x219] indexes Steel/Stone/Wood tables")
&& line.contains("value 2 takes the special suspension-cap path")
&& line.contains("[this+0x251] selects Brick versus Concrete")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("[this+0x252]")
&& line.contains("R10, L10, 12, 14, 16, and 18")
&& line.contains("BridgeDT/BridgeST suspension-cap literals"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.blockers
.iter()
.any(
|line| line.contains("remaining mixed exact compact-prefix classes")
&& line.contains("0xff0000ff/0x0002/0xff is pure bridge")
&& line.contains("0x0005d368/0x0001/0xff is pure track-cap")
&& line.contains("0xff0000ff/0x0001/0xff")
&& line.contains("0x000055f3/0x0001/0xff")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains(
"profile-span mode-family correlations now also split the previous 0x55f3 spans directly"
) && line.contains("span=0x6 rows=72")
&& line.contains("span=0x3 rows=17")
&& line.contains("span=0x27 rows=3"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains(
"exact compact-prefix correlations now split the residual prelude classes directly"
) && line.contains("0x000055f3/0x0001/0xff")
&& line.contains("0xff0000ff/0x0001/0xff")
&& line.contains("0xff0000ff/0x0002/0xff"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("short 0x03-byte post-profile gaps")
&& line.contains("track_cap:2")
&& line.contains("tunnel:15")
&& line.contains("0x000055f3/0x0001/0xff:17"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("sparse 0x27 post-profile outlier")
&& line.contains("0xff0000ff/0x0001/0xff:1")
&& line.contains("0xff0000ff/0x0002/0xff:2")
&& line.contains("TunnelSTBrick_Section.3dp")
&& line.contains("BridgeSTWood_Section.3dp"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("bridge-only two-child class is now grounded save-side")
&& line.contains("0x0002")
&& line.contains("BridgeSTWood_Section.3dp")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line
.contains("0xff0000ff/0x0001/0xff compact-prefix class is now explicit")
&& line.contains("dominant prelude=0x0001/0xff"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line
.contains("0x000055f3/0x0001/0xff compact-prefix class is now explicit")
&& line.contains("dominant prelude=0x0001/0xff"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line
.contains("0xff0000ff/0x0002/0xff compact-prefix class is now explicit")
&& line.contains("dominant prelude="))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("slot +0x44 = 0x004559d0")
&& line.contains("+0x40 = 0x00455fc0")
&& line.contains("+0x4c = 0x00455930"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x004559d0 writing 0x55f1")
&& line.contains("[this+0x206/+0x20a/+0x20e]")
&& line.contains("0x52ec50")
&& line.contains("0x55f3"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("chooser siblings calling 0x00490960 directly")
&& line.contains("0x0048a340")
&& line.contains("0x0048f4c0")
&& line.contains("0x00490200")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line
.contains("0x00490960 copying selector fields into the child object")
&& line.contains("0x00455b70")
&& line.contains("0x005cfd74")
&& line.contains("[this+0x248]"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x00490200 reading the seeded lanes")
&& line.contains("0x006cfca8")
&& line.contains("[this+0x216/+0x218/+0x201/+0x202]"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x0048e140/0x0048e160/0x0048e180")
&& line.contains("[this+0x206/+0x20a/+0x20e]")
&& line.contains("0x0048e1a0")
&& line.contains("[this+0x202]"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x0048ed30")
&& line.contains("[this+0x248]")
&& line.contains("[this+0x08]")
&& line.contains("0x455d20/0x455650/0x53b080"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x004a2eba/0x004a30f9/0x004a339c")
&& line.contains("0x005cb138 = BallastCapDT_Cap.3dp")
&& line.contains("0x004909e2"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("mode 0x0b")
&& line.contains("TrackCapDT/ST_Cap")
&& line.contains("mode 0x03")
&& line.contains("OverpassST_section")
&& line.contains("mode 0x02")
&& line.contains("mode 0x01"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("objdump on 0x00490960")
&& line.contains("stem at [esp+0x14]")
&& line.contains("[esp+0x18]/[esp+0x1c] feed 0x539530")
&& line.contains("[esp+0x20] feeds 0x53a5b0")
&& line.contains("[esp+0x34] gates whether the new child is cached")
&& line.contains("selector-copy block")
&& line.contains("[esp+0x28]/[esp+0x2c]/[esp+0x30]")
&& line.contains("0x0048ed01/0x0048ed20")
&& line.contains("bypass")
&& line.contains("0x004a17eb/0x004a1995/0x004a1b44/0x004a1b7d")
&& line.contains("0x004a1b95")
&& line.contains("arg7/arg8/arg9 = -1/-1/0")
&& line.contains("arg8 fixed at 1")
&& line.contains("arg9 fixed at 0"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x004a17eb/0x004a1995")
&& line.contains("0x621a94/0x621a64")
&& line.contains("one-bit selector (0 or 1)")
&& line.contains("0x004a1b44/0x004a1b7d")
&& line.contains("0x621a9c/0x621a6c")
&& line.contains("0x004a1b95")
&& line.contains("0x0048ed01/0x0048ed20")
&& line.contains("0x005cb198 versus 0x005cb1ac"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("objdump on 0x00455b70")
&& line.contains("[this+0x206/+0x20a/+0x20e]")
&& line.contains("0x51d820")
&& line.contains("0x005c87a8")
&& line.contains("0x005cfd74 = \"Infrastructure\""))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("objdump on 0x51d820")
&& line.contains("owned heap strings")
&& line.contains("0x5a1145")
&& line.contains("0x5a125d")
&& line.contains("byte-for-byte"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("objdump on 0x52ec50")
&& line.contains("bit 5 of [this+0x20]")
&& line.contains("bit 6 of [this+0x20]")
&& line.contains("0x531030"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("objdump on 0x531030/0x5a464d/0x5a44a8")
&& line.contains("0x531030 just forwards")
&& line.contains("0x5a44a8 is the shared chunked stream write path")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("cannot come from selector-copy state alone")
&& line.contains("0xff0000ff/0x0001/0xff")
&& line.contains("dominant TrackCap rows")
&& line.contains("tunnel residue")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(
|line| line.contains("BridgeSTWood_Section.3dp aligns with mode 0x01 Bridge")
&& line.contains("TunnelSTBrick_Cap/Section.3dp with mode 0x02 Tunnel")
&& line.contains("BallastCapST_Cap.3dp with mode 0x0a BallastCap")
&& line.contains("TrackCapST_Cap.3dp with mode 0x0b TrackCap")
)
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains(
"mode-family correlations now also split the candidate patterns directly"
) && line.contains("0x0002/0xff rows=18")
&& line.contains("bridge"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| {
line.contains("0x00518140")
&& line.contains("12-byte row")
&& line.contains("[collection+0x3c]")
})
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x00518380") && line.contains("ordinal"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("0x005181f0/0x00518260")
&& line.contains("previous live id"))
);
assert!(trace.notes.iter().any(|line| {
line.contains("pure bridge-only 0x0002/0xff candidate class is grounded save-side")
&& line.contains("paired DT/ST siblings at 0x004a2c80 and 0x004a34e0")
&& line.contains("grounded top-level branch meaning")
&& line.contains("grounded bridge/tunnel material selector roles")
&& line.contains("concrete child-construction/write-side chain through 0x00490960")
&& line.contains("0x004559d0")
}));
assert!(trace.notes.iter().any(|line| line.contains("ST-only")
&& line.contains("ST chooser sibling")
&& line.contains("DT sibling remains grounded statically")));
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| {
line.contains("0x52ebd0/0x52ec50")
&& (line.contains("bits 0x20/0x40") || line.contains("bits 0x20 and 0x40"))
})
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| {
(line.contains("0x455870/0x455930")
|| (line.contains("0x455870") && line.contains("0x455930")))
&& (line.contains("six 4-byte lanes") || line.contains("six dword lanes"))
})
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| {
line.contains("0x530720")
&& line.contains("0x52e8b0")
&& line.contains("[this+0x4b/+0x4f/+0x53]")
})
);
assert!(
trace.candidate_consumer_hypotheses[2]
.evidence
.iter()
.any(|line| line.contains("0x00448a70")
&& line.contains("[world+0x15e1/+0x162d]")
&& line.contains("0x00448af0")
&& line.contains("[world+0x2139/+0x213d/+0x2141]"))
);
assert!(
trace.candidate_consumer_hypotheses[2]
.evidence
.iter()
.any(|line| line.contains("0x00493660")
&& line.contains("[child+0x218]")
&& line.contains("[child+0x226]")
&& line.contains("0x006cfc9c")
&& line.contains("0x487960"))
);
assert!(
trace.candidate_consumer_hypotheses[2]
.evidence
.iter()
.any(|line| line.contains("0x0048b660")
&& line.contains("[child+0x216]")
&& line.contains("[child+0x201]")
&& line.contains("0x53a350"))
);
assert!(
trace.candidate_consumer_hypotheses[2]
.evidence
.iter()
.any(|line| line.contains("0x0048e2c0")
&& line.contains("bit 0x20 in [child+0x201]")
&& line.contains("0x53a3a0")
&& line.contains("0x48a9e0")
&& line.contains("0x0048e3c0")
&& line.contains("[child+0x22e]")
&& line.contains("0x006cfcb4")
&& line.contains("bit 0x02 in [child+0x24c]"))
);
assert!(
trace.candidate_consumer_hypotheses[0]
.evidence
.iter()
.any(|line| line.contains("u16 child count")
&& line.contains("saved primary-child byte"))
);
assert_eq!(trace.branches[0].status, "grounded_separate_owner_seam");
assert_eq!(trace.branches[1].status, "disproved_by_grounded_probe");
}
}