From 7a26063656e9070280fb4cd5c9b9125f1420a8a5 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sun, 19 Apr 2026 03:02:11 -0700 Subject: [PATCH] Compare building source assets to live bindings --- .../rt3-1.06/building-type-sources.json | 198 ++++++++++++++++++ crates/rrt-cli/src/main.rs | 27 ++- crates/rrt-runtime/src/building.rs | 68 ++++++ crates/rrt-runtime/src/lib.rs | 5 +- docs/rehost-queue.md | 23 +- 5 files changed, 307 insertions(+), 14 deletions(-) diff --git a/artifacts/exports/rt3-1.06/building-type-sources.json b/artifacts/exports/rt3-1.06/building-type-sources.json index 7fb1e2c..5596b7e 100644 --- a/artifacts/exports/rt3-1.06/building-type-sources.json +++ b/artifacts/exports/rt3-1.06/building-type-sources.json @@ -5,6 +5,204 @@ "bca_file_count": 77, "bty_file_count": 200, "unique_canonical_stem_count": 208, + "named_binding_comparison": { + "bindings_path": "artifacts/exports/rt3-1.06/event-effects-building-bindings.json", + "named_binding_count": 67, + "shared_canonical_stem_count": 43, + "binding_only_canonical_stems": [ + "port00", + "port01", + "port02", + "port03", + "port04", + "port05", + "port06", + "port07", + "port08", + "port09", + "port10", + "port11", + "warehouse00", + "warehouse01", + "warehouse02", + "warehouse03", + "warehouse04", + "warehouse05", + "warehouse06", + "warehouse07", + "warehouse08", + "warehouse09", + "warehouse10", + "warehouse11" + ], + "source_only_canonical_stems": [ + "church", + "cinema", + "clpbrdhouse01", + "clpbrdhouse02", + "clpbrdhouse03", + "clpbrdhouse04", + "clpbrdhouse05", + "clpbrdhouse06", + "clpbrdhouse07", + "clpbrdhouse08", + "clpbrdhouse09", + "clpbrdhouse10", + "clpbrdhouse101", + "clpbrdhouse102", + "clpbrdhouse103", + "clpbrdhouse104", + "clpbrdhouse11", + "clpbrdhouse12", + "clpbrdstationlrg", + "clpbrdstationmed", + "clpbrdstationsml", + "commercial", + "commerciallarge01", + "commerciallarge02", + "commercialmedium01", + "commercialmedium02", + "commercialsmall01", + "commercialsmall02", + "concreteplant", + "constructionfirm", + "customshouse", + "departmentstore", + "dummy", + "electronicsplant", + "farmdye", + "furnace", + "hospital", + "hotel", + "house", + "kyotohouse01", + "kyotohouse02", + "kyotohouse03", + "kyotohouse04", + "kyotohouse05", + "kyotohouse06", + "kyotohouse07", + "kyotohouse08", + "kyotohouse09", + "kyotohouse10", + "kyotohouse101", + "kyotohouse102", + "kyotohouse103", + "kyotohouse104", + "kyotohouse11", + "kyotohouse12", + "kyotostationlrg", + "kyotostationmed", + "kyotostationsml", + "largestation", + "machineshop", + "maintenance", + "maintenancefacility", + "mediumstation", + "museum", + "oremine", + "persianhouse01", + "persianhouse02", + "persianhouse03", + "persianhouse04", + "persianhouse05", + "persianhouse06", + "persianhouse07", + "persianhouse08", + "persianhouse09", + "persianhouse10", + "persianhouse101", + "persianhouse102", + "persianhouse103", + "persianhouse104", + "persianhouse11", + "persianhouse12", + "persianstationlrg", + "persianstationmed", + "persianstationsml", + "pharmaceuticalplant", + "port", + "postoffice", + "quarry", + "radiostation", + "restaurant", + "retail", + "retaillrg", + "retailsml", + "saloon", + "schoolhouse", + "servicetower", + "smallstation", + "sowesthouse01", + "sowesthouse02", + "sowesthouse03", + "sowesthouse04", + "sowesthouse05", + "sowesthouse06", + "sowesthouse07", + "sowesthouse08", + "sowesthouse09", + "sowesthouse10", + "sowesthouse101", + "sowesthouse102", + "sowesthouse103", + "sowesthouse104", + "sowesthouse11", + "sowesthouse12", + "soweststationlrg", + "soweststationmed", + "soweststationsml", + "stadium", + "tudorhouse01", + "tudorhouse02", + "tudorhouse03", + "tudorhouse04", + "tudorhouse05", + "tudorhouse06", + "tudorhouse07", + "tudorhouse08", + "tudorhouse09", + "tudorhouse10", + "tudorhouse101", + "tudorhouse102", + "tudorhouse103", + "tudorhouse104", + "tudorhouse11", + "tudorhouse12", + "tudorstationlrg", + "tudorstationmed", + "tudorstationsml", + "victorianhouse01", + "victorianhouse02", + "victorianhouse03", + "victorianhouse04", + "victorianhouse05", + "victorianhouse06", + "victorianhouse07", + "victorianhouse08", + "victorianhouse09", + "victorianhouse10", + "victorianhouse101", + "victorianhouse102", + "victorianhouse103", + "victorianhouse104", + "victorianhouse11", + "victorianhouse12", + "victorianstationlrg", + "victorianstationmed", + "victorianstationsml", + "warehouse", + "windmill", + "z200ftruler", + "z200ftrulercross", + "zsmoke1", + "zsmoke2", + "zsmoke3", + "zsmoke4", + "zsmoke5", + "zsmoke6" + ] + }, "notes": [ "BuildingTypes sources are grouped by a canonical stem that lowercases and strips spaces, underscores, and hyphens so paired .bca/.bty variants collapse onto one asset token.", "This report is an offline asset-pool view only; it does not by itself assign live candidate ids or prove scenario candidate-table availability." diff --git a/crates/rrt-cli/src/main.rs b/crates/rrt-cli/src/main.rs index 82ade61..9ccf640 100644 --- a/crates/rrt-cli/src/main.rs +++ b/crates/rrt-cli/src/main.rs @@ -26,7 +26,7 @@ use rrt_runtime::{ SAVE_SLICE_DOCUMENT_FORMAT_VERSION, SNAPSHOT_FORMAT_VERSION, SmpClassicPackedProfileBlock, SmpInspectionReport, SmpLoadedSaveSlice, SmpRt3105PackedProfileBlock, SmpSaveLoadSummary, WinInspectionReport, compare_save_region_fixed_row_run_candidates, execute_step_command, - extract_pk4_entry_file, inspect_building_types_dir, inspect_campaign_exe_file, + extract_pk4_entry_file, inspect_building_types_dir_with_bindings, inspect_campaign_exe_file, inspect_cargo_economy_sources_with_bindings, inspect_cargo_skin_pk4, inspect_cargo_types_dir, inspect_pk4_file, inspect_save_company_and_chairman_analysis_file, inspect_save_infrastructure_asset_trace_file, inspect_save_periodic_company_service_trace_file, @@ -190,6 +190,7 @@ enum Command { }, RuntimeInspectBuildingTypeSources { building_types_dir: PathBuf, + bindings_path: Option, }, RuntimeInspectCargoSkins { cargo_skin_pk4_path: PathBuf, @@ -1089,8 +1090,14 @@ fn real_main() -> Result<(), Box> { Command::RuntimeInspectCargoTypes { cargo_types_dir } => { run_runtime_inspect_cargo_types(&cargo_types_dir)?; } - Command::RuntimeInspectBuildingTypeSources { building_types_dir } => { - run_runtime_inspect_building_type_sources(&building_types_dir)?; + Command::RuntimeInspectBuildingTypeSources { + building_types_dir, + bindings_path, + } => { + run_runtime_inspect_building_type_sources( + &building_types_dir, + bindings_path.as_deref(), + )?; } Command::RuntimeInspectCargoSkins { cargo_skin_pk4_path, @@ -1395,6 +1402,15 @@ fn parse_command() -> Result> { { Ok(Command::RuntimeInspectBuildingTypeSources { building_types_dir: PathBuf::from(path), + bindings_path: None, + }) + } + [command, subcommand, path, bindings_path] + if command == "runtime" && subcommand == "inspect-building-type-sources" => + { + Ok(Command::RuntimeInspectBuildingTypeSources { + building_types_dir: PathBuf::from(path), + bindings_path: Some(PathBuf::from(bindings_path)), }) } [command, subcommand, path] @@ -1563,7 +1579,7 @@ fn parse_command() -> Result> { }) } _ => Err( - "usage: rrt-cli [validate [repo-root] | finance eval | finance diff | runtime validate-fixture | runtime summarize-fixture | runtime export-fixture-state | runtime diff-state | runtime summarize-state | runtime import-state | runtime inspect-smp | runtime inspect-candidate-table | runtime inspect-compact-event-dispatch-cluster | runtime inspect-compact-event-dispatch-cluster-counts | runtime summarize-save-load | runtime load-save-slice | runtime inspect-save-company-chairman | runtime inspect-save-placed-structure-triplets | runtime compare-region-fixed-row-runs | runtime inspect-periodic-company-service-trace | runtime inspect-region-service-trace | runtime inspect-infrastructure-asset-trace | runtime inspect-save-region-queued-notice-records | runtime inspect-placed-structure-dynamic-side-buffer | runtime inspect-unclassified-save-collections | runtime import-save-state | runtime export-save-slice | runtime export-overlay-import | runtime inspect-pk4 | runtime inspect-cargo-types | runtime inspect-building-type-sources | runtime inspect-cargo-skins | runtime inspect-cargo-economy-sources | runtime inspect-cargo-production-selector | runtime inspect-cargo-price-selector | runtime inspect-win | runtime extract-pk4-entry | runtime inspect-campaign-exe | runtime compare-classic-profile [saveN.gms...] | runtime compare-105-profile [saveN.gms...] | runtime compare-candidate-table [fileN...] | runtime compare-recipe-book-lines [fileN...] | runtime compare-setup-payload-core [fileN...] | runtime compare-setup-launch-payload [fileN...] | runtime compare-post-special-conditions-scalars [fileN...] | runtime scan-candidate-table-headers | runtime scan-special-conditions | runtime scan-aligned-runtime-rule-band | runtime scan-post-special-conditions-scalars | runtime scan-post-special-conditions-tail | runtime scan-recipe-book-lines | runtime export-profile-block ]" + "usage: rrt-cli [validate [repo-root] | finance eval | finance diff | runtime validate-fixture | runtime summarize-fixture | runtime export-fixture-state | runtime diff-state | runtime summarize-state | runtime import-state | runtime inspect-smp | runtime inspect-candidate-table | runtime inspect-compact-event-dispatch-cluster | runtime inspect-compact-event-dispatch-cluster-counts | runtime summarize-save-load | runtime load-save-slice | runtime inspect-save-company-chairman | runtime inspect-save-placed-structure-triplets | runtime compare-region-fixed-row-runs | runtime inspect-periodic-company-service-trace | runtime inspect-region-service-trace | runtime inspect-infrastructure-asset-trace | runtime inspect-save-region-queued-notice-records | runtime inspect-placed-structure-dynamic-side-buffer | runtime inspect-unclassified-save-collections | runtime import-save-state | runtime export-save-slice | runtime export-overlay-import | runtime inspect-pk4 | runtime inspect-cargo-types | runtime inspect-building-type-sources [building-bindings.json] | runtime inspect-cargo-skins | runtime inspect-cargo-economy-sources | runtime inspect-cargo-production-selector | runtime inspect-cargo-price-selector | runtime inspect-win | runtime extract-pk4-entry | runtime inspect-campaign-exe | runtime compare-classic-profile [saveN.gms...] | runtime compare-105-profile [saveN.gms...] | runtime compare-candidate-table [fileN...] | runtime compare-recipe-book-lines [fileN...] | runtime compare-setup-payload-core [fileN...] | runtime compare-setup-launch-payload [fileN...] | runtime compare-post-special-conditions-scalars [fileN...] | runtime scan-candidate-table-headers | runtime scan-special-conditions | runtime scan-aligned-runtime-rule-band | runtime scan-post-special-conditions-scalars | runtime scan-post-special-conditions-tail | runtime scan-recipe-book-lines | runtime export-profile-block ]" .into(), ), } @@ -2225,10 +2241,11 @@ fn run_runtime_inspect_cargo_types( fn run_runtime_inspect_building_type_sources( building_types_dir: &Path, + bindings_path: Option<&Path>, ) -> Result<(), Box> { let report = RuntimeBuildingTypeInspectionOutput { path: building_types_dir.display().to_string(), - inspection: inspect_building_types_dir(building_types_dir)?, + inspection: inspect_building_types_dir_with_bindings(building_types_dir, bindings_path)?, }; println!("{}", serde_json::to_string_pretty(&report)?); Ok(()) diff --git a/crates/rrt-runtime/src/building.rs b/crates/rrt-runtime/src/building.rs index 9af39d7..e42cd74 100644 --- a/crates/rrt-runtime/src/building.rs +++ b/crates/rrt-runtime/src/building.rs @@ -27,12 +27,23 @@ pub struct BuildingTypeSourceEntry { pub file_names: Vec, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BuildingTypeNamedBindingComparison { + pub bindings_path: String, + pub named_binding_count: usize, + pub shared_canonical_stem_count: usize, + pub binding_only_canonical_stems: Vec, + pub source_only_canonical_stems: Vec, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct BuildingTypeSourceReport { pub directory_path: String, pub bca_file_count: usize, pub bty_file_count: usize, pub unique_canonical_stem_count: usize, + #[serde(default)] + pub named_binding_comparison: Option, pub notes: Vec, pub files: Vec, pub entries: Vec, @@ -40,6 +51,13 @@ pub struct BuildingTypeSourceReport { pub fn inspect_building_types_dir( path: &Path, +) -> Result> { + inspect_building_types_dir_with_bindings(path, None) +} + +pub fn inspect_building_types_dir_with_bindings( + path: &Path, + bindings_path: Option<&Path>, ) -> Result> { let mut files = Vec::new(); for entry in fs::read_dir(path)? { @@ -129,20 +147,70 @@ pub fn inspect_building_types_dir( "This report is an offline asset-pool view only; it does not by itself assign live candidate ids or prove scenario candidate-table availability.".to_string(), ]; + let named_binding_comparison = if let Some(bindings_path) = bindings_path { + Some(load_named_binding_comparison(bindings_path, &entries)?) + } else { + None + }; + Ok(BuildingTypeSourceReport { directory_path: path.display().to_string(), bca_file_count, bty_file_count, unique_canonical_stem_count: entries.len(), + named_binding_comparison, notes, files, entries, }) } +fn load_named_binding_comparison( + bindings_path: &Path, + entries: &[BuildingTypeSourceEntry], +) -> Result> { + let artifact = + serde_json::from_str::(&fs::read_to_string(bindings_path)?)?; + let named_binding_stems = artifact + .bindings + .into_iter() + .filter_map(|binding| binding.candidate_name) + .map(|candidate_name| canonicalize_building_stem(&candidate_name)) + .collect::>(); + let source_stems = entries + .iter() + .map(|entry| entry.canonical_stem.clone()) + .collect::>(); + + Ok(BuildingTypeNamedBindingComparison { + bindings_path: bindings_path.display().to_string(), + named_binding_count: named_binding_stems.len(), + shared_canonical_stem_count: named_binding_stems.intersection(&source_stems).count(), + binding_only_canonical_stems: named_binding_stems + .difference(&source_stems) + .cloned() + .collect(), + source_only_canonical_stems: source_stems + .difference(&named_binding_stems) + .cloned() + .collect(), + }) +} + fn canonicalize_building_stem(stem: &str) -> String { stem.chars() .filter(|ch| !matches!(ch, ' ' | '_' | '-')) .flat_map(|ch| ch.to_lowercase()) .collect() } + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +struct BuildingBindingArtifact { + bindings: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize)] +struct BuildingBindingRow { + #[serde(default)] + candidate_name: Option, +} diff --git a/crates/rrt-runtime/src/lib.rs b/crates/rrt-runtime/src/lib.rs index ff6c9b4..e6829d8 100644 --- a/crates/rrt-runtime/src/lib.rs +++ b/crates/rrt-runtime/src/lib.rs @@ -12,8 +12,9 @@ pub mod summary; pub mod win; pub use building::{ - BuildingTypeSourceEntry, BuildingTypeSourceFile, BuildingTypeSourceKind, - BuildingTypeSourceReport, inspect_building_types_dir, + BuildingTypeNamedBindingComparison, BuildingTypeSourceEntry, BuildingTypeSourceFile, + BuildingTypeSourceKind, BuildingTypeSourceReport, inspect_building_types_dir, + inspect_building_types_dir_with_bindings, }; pub use calendar::{CalendarPoint, MONTH_SLOTS_PER_YEAR, PHASE_SLOTS_PER_MONTH, TICKS_PER_PHASE}; pub use campaign_exe::{ diff --git a/docs/rehost-queue.md b/docs/rehost-queue.md index df80381..f69fc7d 100644 --- a/docs/rehost-queue.md +++ b/docs/rehost-queue.md @@ -355,13 +355,22 @@ Working rule: descriptor-side candidate bridge is now checked in across `503..613`, and the honest remaining boundary is the missing non-hook name catalog for candidate ids `67..110` - the new offline `BuildingTypes` source report sharpens that missing name-catalog boundary too: - `runtime inspect-building-type-sources rt3_wineprefix/drive_c/rt3/Data/BuildingTypes` - now reports `77` `.bca` files, `200` `.bty` files, and `208` canonical asset stems, but only - `43` of those canonical stems overlap the live named candidate run `0..66`. The numbered live - `Port00..11` and `Warehouse00..11` names collapse to generic asset stems `Port` and - `Warehouse`, while `165` canonical stems exist only in the broader asset pool. So the - `BuildingTypes` directory is now grounded as a wider offline source catalog, but not yet as a - direct second live candidate-name owner for descriptor-side ids `67..110` + `runtime inspect-building-type-sources rt3_wineprefix/drive_c/rt3/Data/BuildingTypes artifacts/exports/rt3-1.06/event-effects-building-bindings.json` + now reports `77` `.bca` files, `200` `.bty` files, and `208` canonical asset stems. Against + the checked-in named add-building bindings it finds exactly `43` shared canonical stems, + `24` binding-only stems (`Port00..11` and `Warehouse00..11`), and `165` broader asset-only + stems. The numbered live `Port00..11` and `Warehouse00..11` names therefore collapse to + generic asset stems `Port` and `Warehouse` on disk, so the `BuildingTypes` directory is now + grounded as a wider offline source catalog, but not yet as a direct second live candidate-name + owner for descriptor-side ids `67..110` + - the local-runtime builder strip now reinforces that same boundary: + direct disassembly of `0x00418be0` shows the broader placed-structure rebuild lane resolving + its caller-supplied stem only through `0x00416e20 indexed_collection_resolve_live_entry_id_by_stem_string` + against the current live candidate collection, then projecting runtime scratch through + `0x00416ec0` and `0x00418610`. So the broader `BuildingTypes` asset pool is not yet a proven + alternate live owner for descriptor-side add-building candidate ids; current non-hook evidence + still routes stem resolution back through the live candidate collection that tops out at the + contiguous named run `0..66` - the concrete owner strip above that bundle is grounded now too: `0x00433060` is the direct non-direct serializer loop that writes `0x4e99/0x4e9a/0x4e9b`, calls `0x00430d70` per live collection row, and sits beside the sibling `0x00433130` size/load