Add parsers for RT3 language and engine type assets

This commit is contained in:
Jan Petykiewicz 2026-04-21 22:10:04 -07:00
commit 61472bf72d
17 changed files with 32835 additions and 9 deletions

View file

@ -11,7 +11,7 @@ pub(crate) use model::{
ScanCommand,
};
const USAGE: &str = "usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime snapshot-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-candidate-table <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime inspect-compact-event-dispatch-cluster-counts <maps-dir> | runtime inspect-map-title-hints <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime snapshot-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-building-type-sources <BuildingTypes-dir> [building-bindings.json] | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-candidate-table-named-runs <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]";
const USAGE: &str = "usage: rrt-cli [validate [repo-root] | finance eval <snapshot.json> | finance diff <left.json> <right.json> | runtime validate-fixture <fixture.json> | runtime summarize-fixture <fixture.json> | runtime export-fixture-state <fixture.json> <snapshot.json> | runtime diff-state <left.json> <right.json> | runtime summarize-state <snapshot.json> | runtime snapshot-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime inspect-candidate-table <file.smp> | runtime inspect-compact-event-dispatch-cluster <maps-dir> | runtime inspect-compact-event-dispatch-cluster-counts <maps-dir> | runtime inspect-map-title-hints <maps-dir> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime inspect-save-company-chairman <file.smp> | runtime inspect-save-placed-structure-triplets <file.smp> | runtime compare-region-fixed-row-runs <left.gms> <right.gms> | runtime inspect-periodic-company-service-trace <file.smp> | runtime inspect-region-service-trace <file.smp> | runtime inspect-infrastructure-asset-trace <file.smp> | runtime inspect-save-region-queued-notice-records <file.smp> | runtime inspect-placed-structure-dynamic-side-buffer <file.smp> | runtime inspect-unclassified-save-collections <file.smp> | runtime snapshot-save-state <file.smp> <snapshot.json> | runtime export-save-slice <file.smp> <save-slice.json> | runtime export-overlay-import <snapshot.json> <save-slice.json> <overlay-import.json> | runtime inspect-pk4 <file.pk4> | runtime inspect-cargo-types <CargoTypes-dir> | runtime inspect-building-type-sources <BuildingTypes-dir> [building-bindings.json] | runtime inspect-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-production-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-cargo-price-selector <CargoTypes-dir> <Cargo106.PK4> | runtime inspect-lng <file.lng> | runtime inspect-car <file.car> | runtime inspect-lco <file.lco> | runtime inspect-engine-types <EngineTypes-dir> | runtime inspect-imb <file.imb> | runtime inspect-cct <file.cct> | runtime inspect-cgo <file.cgo> | runtime inspect-win <file.win> | runtime extract-pk4-entry <file.pk4> <entry-name> <output-path> | runtime inspect-campaign-exe <RT3.exe> | runtime compare-classic-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-105-profile <save1.gms> <save2.gms> [saveN.gms...] | runtime compare-candidate-table <file1> <file2> [fileN...] | runtime compare-recipe-book-lines <file1> <file2> [fileN...] | runtime compare-setup-payload-core <file1> <file2> [fileN...] | runtime compare-setup-launch-payload <file1> <file2> [fileN...] | runtime compare-post-special-conditions-scalars <file1> <file2> [fileN...] | runtime scan-candidate-table-headers <root-dir> | runtime scan-candidate-table-named-runs <root-dir> | runtime scan-locomotive-catalog-tail <root-dir> | runtime scan-special-conditions <root-dir> | runtime scan-aligned-runtime-rule-band <root-dir> | runtime scan-post-special-conditions-scalars <root-dir> | runtime scan-post-special-conditions-tail <root-dir> | runtime scan-recipe-book-lines <root-dir> | runtime export-profile-block <save.gms> <profile.json>]";
pub(super) fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().skip(1).collect();
@ -134,6 +134,58 @@ mod tests {
);
}
#[test]
fn parses_runtime_lng_inspect_command() {
assert_eq!(
parse(&["runtime", "inspect-lng", "RT3.lng"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectLng {
lng_path: PathBuf::from("RT3.lng"),
}))
);
}
#[test]
fn parses_runtime_engine_type_inspect_commands() {
assert_eq!(
parse(&["runtime", "inspect-car", "Class_QJL.car"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectCar {
car_path: PathBuf::from("Class_QJL.car"),
}))
);
assert_eq!(
parse(&["runtime", "inspect-lco", "Class_QJL.lco"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectLco {
lco_path: PathBuf::from("Class_QJL.lco"),
}))
);
assert_eq!(
parse(&["runtime", "inspect-engine-types", "Data/EngineTypes"]),
Command::Runtime(RuntimeCommand::Inspect(
InspectCommand::InspectEngineTypes {
engine_types_dir: PathBuf::from("Data/EngineTypes"),
}
))
);
assert_eq!(
parse(&["runtime", "inspect-imb", "ice_profile.imb"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectImb {
imb_path: PathBuf::from("ice_profile.imb"),
}))
);
assert_eq!(
parse(&["runtime", "inspect-cct", "Auto_Carrier.cct"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectCct {
cct_path: PathBuf::from("Auto_Carrier.cct"),
}))
);
assert_eq!(
parse(&["runtime", "inspect-cgo", "AutoA.cgo"]),
Command::Runtime(RuntimeCommand::Inspect(InspectCommand::InspectCgo {
cgo_path: PathBuf::from("AutoA.cgo"),
}))
);
}
#[test]
fn parses_runtime_compare_command() {
assert_eq!(
@ -155,4 +207,16 @@ mod tests {
}))
);
}
#[test]
fn parses_runtime_scan_locomotive_catalog_tail_command() {
assert_eq!(
parse(&["runtime", "scan-locomotive-catalog-tail", "root"]),
Command::Runtime(RuntimeCommand::Scan(
ScanCommand::ScanLocomotiveCatalogTail {
root_path: PathBuf::from("root"),
}
))
);
}
}

View file

@ -136,6 +136,27 @@ pub(crate) enum InspectCommand {
cargo_types_dir: PathBuf,
cargo_skin_pk4_path: PathBuf,
},
InspectLng {
lng_path: PathBuf,
},
InspectCar {
car_path: PathBuf,
},
InspectLco {
lco_path: PathBuf,
},
InspectEngineTypes {
engine_types_dir: PathBuf,
},
InspectImb {
imb_path: PathBuf,
},
InspectCct {
cct_path: PathBuf,
},
InspectCgo {
cgo_path: PathBuf,
},
InspectWin {
win_path: PathBuf,
},
@ -186,6 +207,7 @@ pub(crate) enum CompareCommand {
pub(crate) enum ScanCommand {
ScanCandidateTableHeaders { root_path: PathBuf },
ScanCandidateTableNamedRuns { root_path: PathBuf },
ScanLocomotiveCatalogTail { root_path: PathBuf },
ScanSpecialConditions { root_path: PathBuf },
ScanAlignedRuntimeRuleBand { root_path: PathBuf },
ScanPostSpecialConditionsScalars { root_path: PathBuf },

View file

@ -120,6 +120,29 @@ pub(super) fn parse_inspect_command(
cargo_skin_pk4_path: cargo_skin_pk4_path.into(),
})
}
[subcommand, lng_path] if subcommand == "inspect-lng" => Ok(InspectCommand::InspectLng {
lng_path: lng_path.into(),
}),
[subcommand, car_path] if subcommand == "inspect-car" => Ok(InspectCommand::InspectCar {
car_path: car_path.into(),
}),
[subcommand, lco_path] if subcommand == "inspect-lco" => Ok(InspectCommand::InspectLco {
lco_path: lco_path.into(),
}),
[subcommand, engine_types_dir] if subcommand == "inspect-engine-types" => {
Ok(InspectCommand::InspectEngineTypes {
engine_types_dir: engine_types_dir.into(),
})
}
[subcommand, imb_path] if subcommand == "inspect-imb" => Ok(InspectCommand::InspectImb {
imb_path: imb_path.into(),
}),
[subcommand, cct_path] if subcommand == "inspect-cct" => Ok(InspectCommand::InspectCct {
cct_path: cct_path.into(),
}),
[subcommand, cgo_path] if subcommand == "inspect-cgo" => Ok(InspectCommand::InspectCgo {
cgo_path: cgo_path.into(),
}),
[subcommand, win_path] if subcommand == "inspect-win" => Ok(InspectCommand::InspectWin {
win_path: win_path.into(),
}),

View file

@ -46,6 +46,13 @@ pub(super) fn parse_runtime_command(
| "inspect-cargo-economy-sources"
| "inspect-cargo-production-selector"
| "inspect-cargo-price-selector"
| "inspect-lng"
| "inspect-car"
| "inspect-lco"
| "inspect-engine-types"
| "inspect-imb"
| "inspect-cct"
| "inspect-cgo"
| "inspect-win"
| "extract-pk4-entry"
| "inspect-campaign-exe"
@ -62,6 +69,7 @@ pub(super) fn parse_runtime_command(
}
"scan-candidate-table-headers"
| "scan-candidate-table-named-runs"
| "scan-locomotive-catalog-tail"
| "scan-special-conditions"
| "scan-aligned-runtime-rule-band"
| "scan-post-special-conditions-scalars"

View file

@ -2,10 +2,12 @@ use crate::app::command::InspectCommand;
use crate::app::runtime_compare::inspect_candidate_table;
use crate::app::runtime_inspect::{
export_profile_block, extract_pk4_entry, inspect_building_type_sources, inspect_campaign_exe,
inspect_cargo_economy_sources, inspect_cargo_price_selector, inspect_cargo_production_selector,
inspect_cargo_skins, inspect_cargo_types, inspect_compact_event_dispatch_cluster,
inspect_car, inspect_cargo_economy_sources, inspect_cargo_price_selector,
inspect_cargo_production_selector, inspect_cargo_skins, inspect_cargo_types, inspect_cct,
inspect_cgo, inspect_compact_event_dispatch_cluster,
inspect_compact_event_dispatch_cluster_counts, inspect_infrastructure_asset_trace,
inspect_map_title_hints, inspect_periodic_company_service_trace, inspect_pk4,
inspect_engine_types, inspect_imb, inspect_lco, inspect_lng, inspect_map_title_hints,
inspect_periodic_company_service_trace, inspect_pk4,
inspect_placed_structure_dynamic_side_buffer, inspect_region_service_trace,
inspect_save_company_chairman, inspect_save_placed_structure_triplets,
inspect_save_region_queued_notice_records, inspect_smp, inspect_unclassified_save_collections,
@ -70,6 +72,15 @@ pub(super) fn dispatch_inspect(command: InspectCommand) -> Result<(), Box<dyn st
cargo_types_dir,
cargo_skin_pk4_path,
} => inspect_cargo_price_selector(&cargo_types_dir, &cargo_skin_pk4_path),
InspectCommand::InspectLng { lng_path } => inspect_lng(&lng_path),
InspectCommand::InspectCar { car_path } => inspect_car(&car_path),
InspectCommand::InspectLco { lco_path } => inspect_lco(&lco_path),
InspectCommand::InspectEngineTypes { engine_types_dir } => {
inspect_engine_types(&engine_types_dir)
}
InspectCommand::InspectImb { imb_path } => inspect_imb(&imb_path),
InspectCommand::InspectCct { cct_path } => inspect_cct(&cct_path),
InspectCommand::InspectCgo { cgo_path } => inspect_cgo(&cgo_path),
InspectCommand::InspectWin { win_path } => inspect_win(&win_path),
InspectCommand::ExtractPk4Entry {
pk4_path,

View file

@ -7,6 +7,12 @@ use rrt_runtime::inspect::{
CargoEconomySourceReport, CargoSelectorReport, CargoSkinInspectionReport,
CargoTypeInspectionReport,
},
engine_types::{
EngineTypeCarInspectionReport, EngineTypeCctInspectionReport,
EngineTypeCgoInspectionReport, EngineTypeLcoInspectionReport, EngineTypesInspectionReport,
},
imb::ImbInspectionReport,
lng::LngInspectionReport,
pk4::{Pk4ExtractionReport, Pk4InspectionReport},
smp::{
bundle::SmpInspectionReport,
@ -236,6 +242,48 @@ pub(crate) struct RuntimeCargoSelectorInspectionOutput {
pub(crate) selector: CargoSelectorReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeLngInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: LngInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeCarInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: EngineTypeCarInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeLcoInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: EngineTypeLcoInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeImbInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: ImbInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeCctInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: EngineTypeCctInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeCgoInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: EngineTypeCgoInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeEngineTypesInspectionOutput {
pub(crate) path: String,
pub(crate) inspection: EngineTypesInspectionReport,
}
#[derive(Debug, Serialize)]
pub(crate) struct RuntimeWinInspectionOutput {
pub(crate) path: String,

View file

@ -4,9 +4,12 @@ use std::path::Path;
use crate::app::helpers::inspect::build_profile_block_export_document;
use crate::app::reports::inspect::{
RuntimeBuildingTypeInspectionOutput, RuntimeCampaignExeInspectionOutput,
RuntimeCargoEconomyInspectionOutput, RuntimeCargoSelectorInspectionOutput,
RuntimeCargoSkinInspectionOutput, RuntimeCargoTypeInspectionOutput, RuntimePk4ExtractionOutput,
RuntimePk4InspectionOutput, RuntimeProfileBlockExportReport, RuntimeWinInspectionOutput,
RuntimeCarInspectionOutput, RuntimeCargoEconomyInspectionOutput,
RuntimeCargoSelectorInspectionOutput, RuntimeCargoSkinInspectionOutput,
RuntimeCargoTypeInspectionOutput, RuntimeCctInspectionOutput, RuntimeCgoInspectionOutput,
RuntimeEngineTypesInspectionOutput, RuntimeImbInspectionOutput, RuntimeLcoInspectionOutput,
RuntimeLngInspectionOutput, RuntimePk4ExtractionOutput, RuntimePk4InspectionOutput,
RuntimeProfileBlockExportReport, RuntimeWinInspectionOutput,
};
use rrt_runtime::inspect::{
building::inspect_building_types_dir_with_bindings,
@ -15,6 +18,12 @@ use rrt_runtime::inspect::{
inspect_cargo_economy_sources_with_bindings, inspect_cargo_skin_pk4,
inspect_cargo_types_dir,
},
engine_types::{
inspect_car_file, inspect_cct_file, inspect_cgo_file, inspect_engine_types_dir,
inspect_lco_file,
},
imb::inspect_imb_file,
lng::inspect_lng_file,
pk4::{extract_pk4_entry_file, inspect_pk4_file},
smp::bundle::inspect_smp_file,
win::inspect_win_file,
@ -125,6 +134,71 @@ pub(crate) fn inspect_cargo_price_selector(
Ok(())
}
pub(crate) fn inspect_lng(lng_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeLngInspectionOutput {
path: lng_path.display().to_string(),
inspection: inspect_lng_file(lng_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_car(car_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeCarInspectionOutput {
path: car_path.display().to_string(),
inspection: inspect_car_file(car_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_lco(lco_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeLcoInspectionOutput {
path: lco_path.display().to_string(),
inspection: inspect_lco_file(lco_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_engine_types(
engine_types_dir: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeEngineTypesInspectionOutput {
path: engine_types_dir.display().to_string(),
inspection: inspect_engine_types_dir(engine_types_dir)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_imb(imb_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeImbInspectionOutput {
path: imb_path.display().to_string(),
inspection: inspect_imb_file(imb_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_cct(cct_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeCctInspectionOutput {
path: cct_path.display().to_string(),
inspection: inspect_cct_file(cct_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_cgo(cgo_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeCgoInspectionOutput {
path: cgo_path.display().to_string(),
inspection: inspect_cgo_file(cgo_path)?,
};
println!("{}", serde_json::to_string_pretty(&report)?);
Ok(())
}
pub(crate) fn inspect_win(win_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let report = RuntimeWinInspectionOutput {
path: win_path.display().to_string(),

View file

@ -4,8 +4,10 @@ mod smp;
pub(crate) use assets::{
export_profile_block, extract_pk4_entry, inspect_building_type_sources, inspect_campaign_exe,
inspect_cargo_economy_sources, inspect_cargo_price_selector, inspect_cargo_production_selector,
inspect_cargo_skins, inspect_cargo_types, inspect_pk4, inspect_win,
inspect_car, inspect_cargo_economy_sources, inspect_cargo_price_selector,
inspect_cargo_production_selector, inspect_cargo_skins, inspect_cargo_types, inspect_cct,
inspect_cgo, inspect_engine_types, inspect_imb, inspect_lco, inspect_lng, inspect_pk4,
inspect_win,
};
pub(crate) use maps::{
inspect_compact_event_dispatch_cluster, inspect_compact_event_dispatch_cluster_counts,