Preserve engine type side view cohorts
This commit is contained in:
parent
af21b83300
commit
7741dc2087
3 changed files with 265 additions and 12 deletions
|
|
@ -168,6 +168,7 @@ pub struct EngineTypesInspectionReport {
|
|||
pub car_side_view_resource_pk4_match_count: usize,
|
||||
pub car_side_view_resource_pk4_missing_count: usize,
|
||||
pub car_side_view_resource_pk4_missing_counts: BTreeMap<String, usize>,
|
||||
pub car_side_view_resource_pk4_missing_families: Vec<String>,
|
||||
pub car_auxiliary_stem_counts: BTreeMap<String, usize>,
|
||||
pub car_auxiliary_stem_relation_counts: BTreeMap<String, usize>,
|
||||
pub car_auxiliary_stem_distinct_pair_counts: BTreeMap<String, usize>,
|
||||
|
|
@ -184,6 +185,7 @@ pub struct EngineTypesInspectionReport {
|
|||
pub internal_ne_profile_max_percent_of_interface_vram_counts: BTreeMap<String, usize>,
|
||||
pub lco_companion_stem_counts: BTreeMap<String, usize>,
|
||||
pub lco_body_type_label_counts: BTreeMap<String, usize>,
|
||||
pub lco_companion_profile_family_stems: BTreeMap<String, Vec<String>>,
|
||||
pub lco_low_cardinality_lane_counts: BTreeMap<String, BTreeMap<String, usize>>,
|
||||
pub cgo_scalar_value_counts: BTreeMap<String, usize>,
|
||||
pub cgo_scalar_ladder_counts: BTreeMap<String, usize>,
|
||||
|
|
@ -404,7 +406,7 @@ pub fn inspect_engine_types_dir(
|
|||
);
|
||||
let car_side_view_resource_profile_summaries = side_view_imb_pk4_lookup
|
||||
.as_ref()
|
||||
.map(|lookup| lookup.car_side_view_profile_summaries.clone())
|
||||
.map(|lookup| build_side_view_resource_profile_summaries(&family_entries, lookup))
|
||||
.unwrap_or_default();
|
||||
let car_side_view_resource_pk4_match_count = family_entries
|
||||
.iter()
|
||||
|
|
@ -420,6 +422,8 @@ pub fn inspect_engine_types_dir(
|
|||
.filter(|family| family.side_view_resource_found_in_pk4 == Some(false))
|
||||
.filter_map(|family| family.side_view_resource.as_deref()),
|
||||
);
|
||||
let car_side_view_resource_pk4_missing_families =
|
||||
build_car_side_view_resource_pk4_missing_families(&family_entries);
|
||||
let car_auxiliary_stem_counts = count_named_values(
|
||||
family_entries
|
||||
.iter()
|
||||
|
|
@ -523,6 +527,8 @@ pub fn inspect_engine_types_dir(
|
|||
.iter()
|
||||
.filter_map(|family| family.body_type_label.as_deref()),
|
||||
);
|
||||
let lco_companion_profile_family_stems =
|
||||
build_lco_companion_profile_family_stems(&family_entries);
|
||||
let lco_low_cardinality_lane_counts =
|
||||
build_lco_low_cardinality_lane_counts(lco_reports.values());
|
||||
let cgo_scalar_value_counts = count_owned_values(
|
||||
|
|
@ -601,6 +607,7 @@ pub fn inspect_engine_types_dir(
|
|||
car_side_view_resource_pk4_match_count,
|
||||
car_side_view_resource_pk4_missing_count,
|
||||
car_side_view_resource_pk4_missing_counts,
|
||||
car_side_view_resource_pk4_missing_families,
|
||||
car_auxiliary_stem_counts,
|
||||
car_auxiliary_stem_relation_counts,
|
||||
car_auxiliary_stem_distinct_pair_counts,
|
||||
|
|
@ -617,6 +624,7 @@ pub fn inspect_engine_types_dir(
|
|||
internal_ne_profile_max_percent_of_interface_vram_counts,
|
||||
lco_companion_stem_counts,
|
||||
lco_body_type_label_counts,
|
||||
lco_companion_profile_family_stems,
|
||||
lco_low_cardinality_lane_counts,
|
||||
cgo_scalar_value_counts,
|
||||
cgo_scalar_ladder_counts,
|
||||
|
|
@ -642,7 +650,7 @@ struct EngineTypeFamilyBuilder {
|
|||
struct SideViewImbPk4Lookup {
|
||||
path: String,
|
||||
entry_names: BTreeSet<String>,
|
||||
car_side_view_profile_summaries: BTreeMap<String, EngineTypeImbProfileSummary>,
|
||||
imb_profile_summaries_by_entry_name: BTreeMap<String, EngineTypeImbProfileSummary>,
|
||||
internal_ne_profile_texture_size_counts: BTreeMap<String, usize>,
|
||||
internal_ne_profile_horizontal_scale_modifier_counts: BTreeMap<String, usize>,
|
||||
internal_ne_profile_max_percent_of_interface_vram_counts: BTreeMap<String, usize>,
|
||||
|
|
@ -712,24 +720,22 @@ fn load_side_view_imb_pk4_lookup(
|
|||
let bytes = fs::read(&pk4_path)?;
|
||||
let inspection = inspect_pk4_file(&pk4_path)?;
|
||||
let mut entry_names = BTreeSet::new();
|
||||
let mut car_side_view_profile_summaries = BTreeMap::new();
|
||||
let mut imb_profile_summaries_by_entry_name = BTreeMap::new();
|
||||
let mut internal_ne_profile_texture_size_counts = BTreeMap::new();
|
||||
let mut internal_ne_profile_horizontal_scale_modifier_counts = BTreeMap::new();
|
||||
let mut internal_ne_profile_max_percent_of_interface_vram_counts = BTreeMap::new();
|
||||
|
||||
for entry in inspection.entries {
|
||||
entry_names.insert(entry.name.clone());
|
||||
let is_car_side_view = entry.name.starts_with("CarSideView_");
|
||||
let is_imb_profile = entry.name.ends_with(".imb");
|
||||
let is_internal_ne = entry.name.ends_with("_NE.imb");
|
||||
if !(is_car_side_view || is_internal_ne) {
|
||||
if !is_imb_profile {
|
||||
continue;
|
||||
}
|
||||
|
||||
let payload = &bytes[entry.payload_absolute_offset..entry.payload_end_offset];
|
||||
let imb_profile = summarize_imb_profile(&inspect_imb_bytes(payload)?);
|
||||
if is_car_side_view {
|
||||
car_side_view_profile_summaries.insert(entry.name.clone(), imb_profile.clone());
|
||||
}
|
||||
imb_profile_summaries_by_entry_name.insert(entry.name.clone(), imb_profile.clone());
|
||||
if is_internal_ne {
|
||||
if let (Some(width), Some(height)) =
|
||||
(imb_profile.texture_width, imb_profile.texture_height)
|
||||
|
|
@ -754,7 +760,7 @@ fn load_side_view_imb_pk4_lookup(
|
|||
Ok(Some(SideViewImbPk4Lookup {
|
||||
path: pk4_path.display().to_string(),
|
||||
entry_names,
|
||||
car_side_view_profile_summaries,
|
||||
imb_profile_summaries_by_entry_name,
|
||||
internal_ne_profile_texture_size_counts,
|
||||
internal_ne_profile_horizontal_scale_modifier_counts,
|
||||
internal_ne_profile_max_percent_of_interface_vram_counts,
|
||||
|
|
@ -1110,6 +1116,61 @@ fn build_lco_low_cardinality_lane_counts<'a>(
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn build_car_side_view_resource_pk4_missing_families(
|
||||
families: &[EngineTypeFamilyEntry],
|
||||
) -> Vec<String> {
|
||||
let mut stems = families
|
||||
.iter()
|
||||
.filter(|family| family.side_view_resource_found_in_pk4 == Some(false))
|
||||
.map(|family| family.canonical_stem.clone())
|
||||
.collect::<Vec<_>>();
|
||||
stems.sort();
|
||||
stems
|
||||
}
|
||||
|
||||
fn build_lco_companion_profile_family_stems(
|
||||
families: &[EngineTypeFamilyEntry],
|
||||
) -> BTreeMap<String, Vec<String>> {
|
||||
let mut grouped = BTreeMap::<String, Vec<String>>::new();
|
||||
for family in families {
|
||||
let Some(companion_stem) = family.companion_stem.as_deref() else {
|
||||
continue;
|
||||
};
|
||||
let body_type_label = family.body_type_label.as_deref().unwrap_or("(none)");
|
||||
let side_view_resource = family.side_view_resource.as_deref().unwrap_or("(none)");
|
||||
grouped
|
||||
.entry(format!(
|
||||
"companion={companion_stem} / body={body_type_label} / side_view={side_view_resource}"
|
||||
))
|
||||
.or_default()
|
||||
.push(family.canonical_stem.clone());
|
||||
}
|
||||
for stems in grouped.values_mut() {
|
||||
stems.sort();
|
||||
}
|
||||
grouped
|
||||
}
|
||||
|
||||
fn build_side_view_resource_profile_summaries(
|
||||
families: &[EngineTypeFamilyEntry],
|
||||
lookup: &SideViewImbPk4Lookup,
|
||||
) -> BTreeMap<String, EngineTypeImbProfileSummary> {
|
||||
let mut summaries = BTreeMap::new();
|
||||
for resource_name in families
|
||||
.iter()
|
||||
.filter_map(|family| family.side_view_resource.as_deref())
|
||||
{
|
||||
let Some(summary) = lookup
|
||||
.imb_profile_summaries_by_entry_name
|
||||
.get(resource_name)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
summaries.insert(resource_name.to_string(), summary.clone());
|
||||
}
|
||||
summaries
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -1438,6 +1499,122 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collects_missing_side_view_resource_family_stems() {
|
||||
let missing = build_car_side_view_resource_pk4_missing_families(&[
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "zephyrl".to_string(),
|
||||
side_view_resource_found_in_pk4: Some(false),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "gp35l".to_string(),
|
||||
side_view_resource_found_in_pk4: Some(false),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "gp7".to_string(),
|
||||
side_view_resource_found_in_pk4: Some(true),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
]);
|
||||
|
||||
assert_eq!(missing, vec!["gp35l".to_string(), "zephyrl".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groups_lco_companion_profiles_by_companion_body_and_side_view() {
|
||||
let grouped = build_lco_companion_profile_family_stems(&[
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "gp35l".to_string(),
|
||||
companion_stem: Some("Zephyr".to_string()),
|
||||
side_view_resource: Some("CarSideView_3.imb".to_string()),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "u1l".to_string(),
|
||||
companion_stem: Some("Zephyr".to_string()),
|
||||
side_view_resource: Some("CarSideView_3.imb".to_string()),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "gp7".to_string(),
|
||||
companion_stem: Some("VL80T".to_string()),
|
||||
body_type_label: Some("Loco".to_string()),
|
||||
side_view_resource: Some("CarSideView_1.imb".to_string()),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
]);
|
||||
|
||||
assert_eq!(
|
||||
grouped.get("companion=Zephyr / body=(none) / side_view=CarSideView_3.imb"),
|
||||
Some(&vec!["gp35l".to_string(), "u1l".to_string()])
|
||||
);
|
||||
assert_eq!(
|
||||
grouped.get("companion=VL80T / body=Loco / side_view=CarSideView_1.imb"),
|
||||
Some(&vec!["gp7".to_string()])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_profile_summaries_for_all_referenced_side_view_resources() {
|
||||
let summaries = build_side_view_resource_profile_summaries(
|
||||
&[
|
||||
EngineTypeFamilyEntry {
|
||||
side_view_resource: Some("CarSideView_1.imb".to_string()),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
EngineTypeFamilyEntry {
|
||||
side_view_resource: Some("GP7D_Profile.imb".to_string()),
|
||||
..minimal_family_entry()
|
||||
},
|
||||
],
|
||||
&SideViewImbPk4Lookup {
|
||||
path: "rt3_2IMB.PK4".to_string(),
|
||||
entry_names: BTreeSet::new(),
|
||||
imb_profile_summaries_by_entry_name: BTreeMap::from([
|
||||
(
|
||||
"CarSideView_1.imb".to_string(),
|
||||
EngineTypeImbProfileSummary {
|
||||
tga_name: Some("CarSideView_1".to_string()),
|
||||
texture_width: Some(512),
|
||||
texture_height: Some(512),
|
||||
target_screen_width: None,
|
||||
target_screen_height: None,
|
||||
horizontal_scale_modifier: None,
|
||||
max_percent_of_interface_vram: Some(0.04),
|
||||
image_rect_scaled: None,
|
||||
},
|
||||
),
|
||||
(
|
||||
"GP7D_Profile.imb".to_string(),
|
||||
EngineTypeImbProfileSummary {
|
||||
tga_name: Some("GP7D_Profile".to_string()),
|
||||
texture_width: Some(256),
|
||||
texture_height: Some(128),
|
||||
target_screen_width: None,
|
||||
target_screen_height: None,
|
||||
horizontal_scale_modifier: Some(0.75),
|
||||
max_percent_of_interface_vram: Some(0.09),
|
||||
image_rect_scaled: None,
|
||||
},
|
||||
),
|
||||
]),
|
||||
internal_ne_profile_texture_size_counts: BTreeMap::new(),
|
||||
internal_ne_profile_horizontal_scale_modifier_counts: BTreeMap::new(),
|
||||
internal_ne_profile_max_percent_of_interface_vram_counts: BTreeMap::new(),
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(summaries.len(), 2);
|
||||
assert_eq!(
|
||||
summaries
|
||||
.get("GP7D_Profile.imb")
|
||||
.and_then(|summary| summary.tga_name.as_deref()),
|
||||
Some("GP7D_Profile")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_cgo_content_stems_to_matching_cct_values() {
|
||||
let families = vec![
|
||||
|
|
@ -1559,4 +1736,27 @@ mod tests {
|
|||
assert_eq!(report.entries[0].primary_display_name, "2-D-2");
|
||||
assert!(report.entries[0].matches_grounded_prefix_name);
|
||||
}
|
||||
|
||||
fn minimal_family_entry() -> EngineTypeFamilyEntry {
|
||||
EngineTypeFamilyEntry {
|
||||
canonical_stem: "family".to_string(),
|
||||
car_file: None,
|
||||
lco_file: None,
|
||||
cgo_file: None,
|
||||
cct_file: None,
|
||||
primary_display_name: None,
|
||||
content_name: None,
|
||||
internal_stem: None,
|
||||
auxiliary_stem: None,
|
||||
side_view_resource: None,
|
||||
side_view_resource_found_in_pk4: None,
|
||||
companion_stem: None,
|
||||
body_type_label: None,
|
||||
internal_ne_profile_name: None,
|
||||
internal_ne_profile_found_in_pk4: None,
|
||||
cct_identifier: None,
|
||||
cct_value: None,
|
||||
has_matched_locomotive_pair: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue