From c9026bd1a0bd908488e3f2bc24d239f0f1e466ab Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 19 Apr 2026 15:09:09 -0700 Subject: [PATCH] Classify nonzero stock building header family --- crates/rrt-runtime/src/building.rs | 65 ++++++++++++++++++- .../map-and-scenario-content-load.md | 6 ++ ...ntime-roots-camera-and-support-families.md | 14 ++-- docs/rehost-queue.md | 12 +++- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/crates/rrt-runtime/src/building.rs b/crates/rrt-runtime/src/building.rs index 1a3e4c4..0e892a8 100644 --- a/crates/rrt-runtime/src/building.rs +++ b/crates/rrt-runtime/src/building.rs @@ -92,6 +92,15 @@ pub struct BuildingTypeRecoveredTableSummary { pub present_style_station_entries: Vec, pub present_standalone_entries: Vec, pub bare_port_warehouse_files: Vec, + pub nonzero_bty_header_dword_summaries: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BuildingTypeBtyHeaderDwordSummary { + pub dword_0xbb: u32, + pub dword_0xbb_hex: String, + pub file_count: usize, + pub sample_file_names: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -437,6 +446,33 @@ fn summarize_recovered_table_families( bare_port_warehouse_files.sort(); bare_port_warehouse_files.dedup(); + let mut nonzero_bty_header_dword_groups = BTreeMap::>::new(); + for file in files { + let Some(probe) = &file.bty_header_probe else { + continue; + }; + if probe.dword_0xbb == 0 { + continue; + } + nonzero_bty_header_dword_groups + .entry(probe.dword_0xbb) + .or_default() + .push(file.file_name.clone()); + } + let nonzero_bty_header_dword_summaries = nonzero_bty_header_dword_groups + .into_iter() + .map(|(dword_0xbb, mut file_names)| { + file_names.sort(); + file_names.dedup(); + BuildingTypeBtyHeaderDwordSummary { + dword_0xbb, + dword_0xbb_hex: format!("0x{dword_0xbb:08x}"), + file_count: file_names.len(), + sample_file_names: file_names.into_iter().take(24).collect(), + } + }) + .collect(); + BuildingTypeRecoveredTableSummary { recovered_style_themes: RECOVERED_STYLE_THEMES .into_iter() @@ -449,6 +485,7 @@ fn summarize_recovered_table_families( present_style_station_entries, present_standalone_entries, bare_port_warehouse_files, + nonzero_bty_header_dword_summaries, } } @@ -549,7 +586,24 @@ mod tests { source_kind: BuildingTypeSourceKind::Bty, byte_len: None, bca_selector_probe: None, - bty_header_probe: None, + bty_header_probe: Some(BuildingTypeBtyHeaderProbe { + type_id: 0x03ec, + type_id_hex: "0x000003ec".to_string(), + name_0x04: "Port".to_string(), + name_0x22: "Port".to_string(), + name_0x40: "Port".to_string(), + name_0x5e: "TextileMill".to_string(), + name_0x7c: "Port".to_string(), + name_0x9a: "Port".to_string(), + byte_0xb8: 0x06, + byte_0xb8_hex: "0x06".to_string(), + byte_0xb9: 0x06, + byte_0xb9_hex: "0x06".to_string(), + byte_0xba: 0x30, + byte_0xba_hex: "0x30".to_string(), + dword_0xbb: 0x01f4, + dword_0xbb_hex: "0x000001f4".to_string(), + }), }, BuildingTypeSourceFile { file_name: "Warehouse.bca".to_string(), @@ -577,5 +631,14 @@ mod tests { summary.bare_port_warehouse_files, vec!["Port.bty".to_string(), "Warehouse.bca".to_string()] ); + assert_eq!(summary.nonzero_bty_header_dword_summaries.len(), 1); + assert_eq!( + summary.nonzero_bty_header_dword_summaries[0].dword_0xbb_hex, + "0x000001f4" + ); + assert_eq!( + summary.nonzero_bty_header_dword_summaries[0].sample_file_names, + vec!["Port.bty".to_string()] + ); } } diff --git a/docs/control-loop-atlas/map-and-scenario-content-load.md b/docs/control-loop-atlas/map-and-scenario-content-load.md index b0de2cb..0696412 100644 --- a/docs/control-loop-atlas/map-and-scenario-content-load.md +++ b/docs/control-loop-atlas/map-and-scenario-content-load.md @@ -84,6 +84,12 @@ `Maintenance Facility` and `Service Tower` with zero `dword_0xbb`. So the later numbered `Port%02d` / `Warehouse%02d` clone seam is now bounded above the bare `Port` / `Warehouse` family itself rather than under a hidden station-style alias family in `BuildingTypes`. + The wider nonzero stock family is explicit now too: the recovered report shows only one nonzero + `.bty` header lane, `dword_0xbb = 0x000001f4`, and it spans exactly `22` files including + `Port.bty`, `Warehouse.bty`, and a smaller industrial/commercial subset such as `Brewery`, + `ConcretePlant`, `ConstructionFirm`, `Hospital`, `Museum`, `PaperMill`, and `Steel Mill`. So + the later numbered clone seam is now bounded above that narrower `0x000001f4` stock family + rather than above the full style/source strip. The fixed tail is explicit now too: `0x00444dd0` writes one direct dword from `[world+0x19]`, one zeroed `0x1f4`-byte slab under `0x32cf`, closes the package, derives the diff --git a/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md b/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md index 3de3166..b1a5c23 100644 --- a/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md +++ b/docs/control-loop-atlas/runtime-roots-camera-and-support-families.md @@ -1314,10 +1314,16 @@ `name_0x7c = VictorianStations` and `dword_0xbb = 0x00000000`. The standalone `Maintenance.bty` / `ServiceTower.bty` rows also stay in that stock family, but their display names are `Maintenance Facility` and `Service Tower` and their `dword_0xbb` lane remains zero. - So the numbered `Port%02d` / `Warehouse%02d` seam is no longer plausibly a hidden station-style - alias family under the stock assets; the remaining open question is why the later clone chooser - favors the bare `Port` / `Warehouse` family over those zero-valued station and maintenance / - service rows. + The nonzero stock family above that seam is explicit now too: the recovered report exposes only + one nonzero `.bty` header lane, `dword_0xbb = 0x000001f4`, spanning exactly `22` files + (`Brewery`, `ConcretePlant`, `ConstructionFirm`, `DairyProcessor`, `Distillery`, + `ElectronicsPlant`, `Furnace`, `FurnitureFactory`, `Hospital`, `Lumbermill`, `MachineShop`, + `MeatPackingPlant`, `Museum`, `PaperMill`, `PharmaceuticalPlant`, `Port`, `Recycling Plant`, + `Steel Mill`, `Textile Mill`, `Tire Factory`, `Tool and Die`, and `Warehouse`). So the + numbered `Port%02d` / `Warehouse%02d` seam is no longer plausibly a hidden station-style alias + family under the stock assets; the remaining open question is why the later clone chooser favors + this narrower `0x000001f4` stock family over the zero-valued station and maintenance / service + rows. The direct `+0xba/+0xbb` writer census now rules out a broad false lead too. The obvious new stores at `0x004ecd42/0x004ecdaa` and `0x004ed5d5/0x004ed625` are only shell-side portrait/string refresh helpers over a different id-keyed collection rooted through diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index 32c604a..c6122d6 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -850,11 +850,17 @@ Working rule: as `VictorianStationSml/Med/Lrg.bty` stay on the same `0x000003ec` family but keep `name_0x7c = VictorianStations` and `dword_0xbb = 0x00000000`. The standalone `Maintenance.bty` / `ServiceTower.bty` rows also stay in the same stock family, but expose - display names `Maintenance Facility` and `Service Tower` with zero `dword_0xbb`. So the + display names `Maintenance Facility` and `Service Tower` with zero `dword_0xbb`. The stock + nonzero family is explicit now too: only one recovered `.bty` header lane is nonzero, + `dword_0xbb = 0x000001f4`, and it spans exactly `22` files: + `Brewery`, `ConcretePlant`, `ConstructionFirm`, `DairyProcessor`, `Distillery`, + `ElectronicsPlant`, `Furnace`, `FurnitureFactory`, `Hospital`, `Lumbermill`, `MachineShop`, + `MeatPackingPlant`, `Museum`, `PaperMill`, `PharmaceuticalPlant`, `Port`, `Recycling Plant`, + `Steel Mill`, `Textile Mill`, `Tire Factory`, `Tool and Die`, and `Warehouse`. So the remaining Tier-2 source question is no longer whether the numbered `Port%02d` / `Warehouse%02d` banks are hidden station-style aliases; it is why the later clone path prefers - the bare `Port` / `Warehouse` family over the zero-valued station and maintenance/service - families when it seeds those numbered banks. + this narrower `0x000001f4` stock family over the zero-valued station and + maintenance/service families when it seeds those numbered banks. The direct `+0xba/+0xbb` writer census is narrower now too. The obvious newly surfaced stores at `0x004ecd42/0x004ecdaa` and `0x004ed5d5/0x004ed625` are only shell-side portrait/string refresh helpers: they walk a separate id-keyed collection through `0x0053f830`, free and