Widen save-native company stat-band windows

This commit is contained in:
Jan Petykiewicz 2026-04-17 20:49:07 -07:00
commit f52df7d233
4 changed files with 66 additions and 147 deletions

View file

@ -3070,27 +3070,27 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
build_save_dword_candidate(&bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_0cfb_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(&bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_0d7f_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(&bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_1c47_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_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,
@ -3498,6 +3498,7 @@ 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 = 16;
const SAVE_COMPANY_RECORD_SCALAR_CANDIDATE_FIELDS: [(&str, usize); 7] = [
("mutable_support_scalar", 0x4f),
("young_company_support_scalar", 0x57),
@ -3527,108 +3528,6 @@ const SAVE_COMPANY_RECORD_POST_CAPACITY_CANDIDATE_FIELDS: [(&str, usize); 6] = [
("post_capacity_word_5", 0x7694),
("post_capacity_word_6", 0x7698),
];
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_CANDIDATE_FIELDS: [(&str, usize); 8] = [
(
"stat_band_0cfb_word_1",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET,
),
(
"stat_band_0cfb_word_2",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 4,
),
(
"stat_band_0cfb_word_3",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 8,
),
(
"stat_band_0cfb_word_4",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 12,
),
(
"stat_band_0cfb_word_5",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 16,
),
(
"stat_band_0cfb_word_6",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 20,
),
(
"stat_band_0cfb_word_7",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 24,
),
(
"stat_band_0cfb_word_8",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET + 28,
),
];
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_CANDIDATE_FIELDS: [(&str, usize); 8] = [
(
"stat_band_0d7f_word_1",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET,
),
(
"stat_band_0d7f_word_2",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 4,
),
(
"stat_band_0d7f_word_3",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 8,
),
(
"stat_band_0d7f_word_4",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 12,
),
(
"stat_band_0d7f_word_5",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 16,
),
(
"stat_band_0d7f_word_6",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 20,
),
(
"stat_band_0d7f_word_7",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 24,
),
(
"stat_band_0d7f_word_8",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET + 28,
),
];
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_CANDIDATE_FIELDS: [(&str, usize); 8] = [
(
"stat_band_1c47_word_1",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET,
),
(
"stat_band_1c47_word_2",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 4,
),
(
"stat_band_1c47_word_3",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 8,
),
(
"stat_band_1c47_word_4",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 12,
),
(
"stat_band_1c47_word_5",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 16,
),
(
"stat_band_1c47_word_6",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 20,
),
(
"stat_band_1c47_word_7",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 24,
),
(
"stat_band_1c47_word_8",
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET + 28,
),
];
const SAVE_COMPANY_RECORD_START_SCAN_LIMIT: usize = 0x120;
const SAVE_CHAIRMAN_RECORD_NAME_OFFSET: usize = 0x08;
@ -3754,27 +3653,27 @@ fn parse_save_company_roster_probe(
bytes,
record_offset + SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET,
)?;
let stat_band_root_0cfb_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_0d7f_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_CANDIDATE_FIELDS
.iter()
.map(|(label, relative_offset)| {
build_save_dword_candidate(bytes, record_offset, label, *relative_offset)
})
.collect::<Option<Vec<_>>>()?;
let stat_band_root_1c47_candidates =
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_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(SmpLoadedCompanyRosterEntry {
company_id,
active,
@ -3848,6 +3747,22 @@ fn runtime_company_stat_band_candidate_from_save(
}
}
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 detect_save_company_record_start_offset(
bytes: &[u8],
header_probe: &SmpSaveTaggedCollectionHeaderProbe,