Make cargo catalog save-native

This commit is contained in:
Jan Petykiewicz 2026-04-16 14:47:38 -07:00
commit c17b9f55f7
24 changed files with 575 additions and 52 deletions

View file

@ -68,7 +68,10 @@ metadata still does not ground, such as `All Factory Production`, now remain exp
unmapped world-condition and world-descriptor
frontier buckets still remain where current checked-in metadata stops, and
`blocked_missing_locomotive_catalog_context` is now reserved for intentionally incomplete save-side
catalog context instead of the normal save-slice path. Shell purchase-flow, Trainbuy refresh,
catalog context instead of the normal save-slice path. Cargo slot identity is now save-native too:
the recipe-book probe lowers into `RuntimeState.cargo_catalog`, so save-slice documents can carry
slot labels and token-stem evidence alongside the executable `cargo_production_overrides` surface
without introducing a live cargo-economy model. Shell purchase-flow, Trainbuy refresh,
cached locomotive-rating recomputation, and selected-profile parity remain out of scope. Mixed
supported/unsupported real rows still stay parity-only. The PE32 hook remains useful as capture and
integration tooling, but it is no longer the main execution milestone.

View file

@ -4483,6 +4483,8 @@ mod tests {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-condition-parity-save-slice-fixture.json",
);
let cargo_catalog_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../fixtures/runtime/packed-event-cargo-catalog-save-slice-fixture.json");
run_runtime_summarize_fixture(&parity_fixture)
.expect("save-slice-backed parity fixture should summarize");
@ -4522,6 +4524,8 @@ mod tests {
.expect("save-slice-backed executable world-scalar condition fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture)
.expect("save-slice-backed parity world-scalar condition fixture should summarize");
run_runtime_summarize_fixture(&cargo_catalog_fixture)
.expect("save-slice-backed cargo catalog fixture should summarize");
}
#[test]
@ -4548,6 +4552,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: None,
notes: vec!["exported for test".to_string()],

View file

@ -178,6 +178,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -265,6 +266,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: None,
notes: vec![],
@ -353,6 +355,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -383,6 +386,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(
rrt_runtime::SmpLoadedEventRuntimeCollectionSummary {

View file

@ -80,6 +80,8 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub locomotive_catalog_count: Option<usize>,
#[serde(default)]
pub cargo_catalog_count: Option<usize>,
#[serde(default)]
pub territory_count: Option<usize>,
#[serde(default)]
pub company_territory_track_count: Option<usize>,
@ -469,6 +471,14 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(count) = self.cargo_catalog_count {
if actual.cargo_catalog_count != count {
mismatches.push(format!(
"cargo_catalog_count mismatch: expected {count}, got {}",
actual.cargo_catalog_count
));
}
}
if let Some(count) = self.territory_count {
if actual.territory_count != count {
mismatches.push(format!(

View file

@ -5,17 +5,17 @@ use serde::{Deserialize, Serialize};
use crate::persistence::{load_runtime_snapshot_document, validate_runtime_snapshot_document};
use crate::{
CalendarPoint, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind,
RuntimeCompanyTarget, RuntimeCondition, RuntimeEffect, RuntimeEventRecord,
RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary,
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
RuntimeServiceState, RuntimeState, RuntimeTerritoryTarget, RuntimeWorldRestoreState,
SmpLoadedPackedEventConditionRowSummary, SmpLoadedPackedEventGroupedEffectRowSummary,
SmpLoadedPackedEventNegativeSentinelScopeSummary, SmpLoadedPackedEventRecordSummary,
SmpLoadedPackedEventTextBandSummary, SmpLoadedSaveSlice,
CalendarPoint, RuntimeCargoCatalogEntry, RuntimeCompanyConditionTestScope,
RuntimeCompanyControllerKind, RuntimeCompanyTarget, RuntimeCondition, RuntimeEffect,
RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry,
RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary,
RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary,
RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary,
RuntimePackedEventTextBandSummary, RuntimePlayerConditionTestScope, RuntimePlayerTarget,
RuntimeSaveProfileState, RuntimeServiceState, RuntimeState, RuntimeTerritoryTarget,
RuntimeWorldRestoreState, SmpLoadedPackedEventConditionRowSummary,
SmpLoadedPackedEventGroupedEffectRowSummary, SmpLoadedPackedEventNegativeSentinelScopeSummary,
SmpLoadedPackedEventRecordSummary, SmpLoadedPackedEventTextBandSummary, SmpLoadedSaveSlice,
};
pub const STATE_DUMP_FORMAT_VERSION: u32 = 1;
@ -96,6 +96,7 @@ struct SaveSliceProjection {
candidate_availability: BTreeMap<String, u32>,
named_locomotive_availability: BTreeMap<String, u32>,
locomotive_catalog: Option<Vec<RuntimeLocomotiveCatalogEntry>>,
cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>,
named_locomotive_cost: BTreeMap<String, u32>,
cargo_production_overrides: BTreeMap<u32, u32>,
special_conditions: BTreeMap<String, u32>,
@ -245,6 +246,7 @@ pub fn project_save_slice_to_runtime_state_import(
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: projection.locomotive_catalog.unwrap_or_default(),
cargo_catalog: projection.cargo_catalog.unwrap_or_default(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -309,6 +311,9 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
locomotive_catalog: projection
.locomotive_catalog
.unwrap_or_else(|| base_state.locomotive_catalog.clone()),
cargo_catalog: projection
.cargo_catalog
.unwrap_or_else(|| base_state.cargo_catalog.clone()),
territories: base_state.territories.clone(),
company_territory_track_piece_counts: base_state
.company_territory_track_piece_counts
@ -359,6 +364,10 @@ fn project_save_slice_components(
save_slice.locomotive_catalog.is_some()
|| save_slice.named_locomotive_availability_table.is_some(),
);
world_flags.insert(
"save_slice.cargo_catalog_present".to_string(),
save_slice.cargo_catalog.is_some(),
);
world_flags.insert(
"save_slice.event_runtime_collection_present".to_string(),
save_slice.event_runtime_collection.is_some(),
@ -690,6 +699,44 @@ fn project_save_slice_components(
} else {
None
};
let cargo_catalog = if let Some(catalog) = &save_slice.cargo_catalog {
metadata.insert(
"save_slice.cargo_catalog_source_kind".to_string(),
catalog.source_kind.clone(),
);
metadata.insert(
"save_slice.cargo_catalog_semantic_family".to_string(),
catalog.semantic_family.clone(),
);
metadata.insert(
"save_slice.cargo_catalog_entry_count".to_string(),
catalog.observed_entry_count.to_string(),
);
if let Some(root_offset) = catalog.root_offset {
metadata.insert(
"save_slice.cargo_catalog_root_offset".to_string(),
root_offset.to_string(),
);
}
Some(
catalog
.entries
.iter()
.map(|entry| RuntimeCargoCatalogEntry {
slot_id: entry.slot_id,
label: entry.label.clone(),
supplied_token_stem: entry
.supplied_cargo_token_probable_high16_ascii_stem
.clone(),
demanded_token_stem: entry
.demanded_cargo_token_probable_high16_ascii_stem
.clone(),
})
.collect::<Vec<_>>(),
)
} else {
None
};
let named_locomotive_cost = BTreeMap::new();
let cargo_production_overrides = BTreeMap::new();
@ -702,8 +749,11 @@ fn project_save_slice_components(
.collect();
}
let (packed_event_collection, event_runtime_records) =
project_packed_event_collection(save_slice, &packed_event_context)?;
let (packed_event_collection, event_runtime_records) = project_packed_event_collection(
save_slice,
&packed_event_context,
cargo_catalog.as_deref().unwrap_or(&[]),
)?;
if let Some(summary) = &save_slice.event_runtime_collection {
metadata.insert(
"save_slice.event_runtime_collection_source_kind".to_string(),
@ -741,6 +791,7 @@ fn project_save_slice_components(
candidate_availability,
named_locomotive_availability,
locomotive_catalog,
cargo_catalog,
named_locomotive_cost,
cargo_production_overrides,
special_conditions,
@ -750,6 +801,7 @@ fn project_save_slice_components(
fn project_packed_event_collection(
save_slice: &SmpLoadedSaveSlice,
company_context: &ImportRuntimeContext,
cargo_catalog: &[RuntimeCargoCatalogEntry],
) -> Result<
(
Option<RuntimePackedEventCollectionSummary>,
@ -780,6 +832,7 @@ fn project_packed_event_collection(
runtime_packed_event_record_summary_from_smp(
record,
company_context,
cargo_catalog,
imported_record_ids.contains(&record.live_entry_id),
)
})
@ -810,6 +863,7 @@ fn project_packed_event_collection(
fn runtime_packed_event_record_summary_from_smp(
record: &SmpLoadedPackedEventRecordSummary,
company_context: &ImportRuntimeContext,
cargo_catalog: &[RuntimeCargoCatalogEntry],
imported: bool,
) -> RuntimePackedEventRecordSummary {
let lowered_decoded_conditions = lowered_record_decoded_conditions(record, company_context)
@ -840,7 +894,7 @@ fn runtime_packed_event_record_summary_from_smp(
standalone_condition_rows: record
.standalone_condition_rows
.iter()
.map(runtime_packed_event_condition_row_summary_from_smp)
.map(|row| runtime_packed_event_condition_row_summary_from_smp(row, cargo_catalog))
.collect(),
negative_sentinel_scope: record
.negative_sentinel_scope
@ -850,7 +904,7 @@ fn runtime_packed_event_record_summary_from_smp(
grouped_effect_rows: record
.grouped_effect_rows
.iter()
.map(runtime_packed_event_grouped_effect_row_summary_from_smp)
.map(|row| runtime_packed_event_grouped_effect_row_summary_from_smp(row, cargo_catalog))
.collect(),
grouped_company_targets: classify_real_grouped_company_targets(record),
decoded_conditions: lowered_decoded_conditions,
@ -906,7 +960,11 @@ fn runtime_packed_event_text_band_summary_from_smp(
fn runtime_packed_event_condition_row_summary_from_smp(
row: &crate::SmpLoadedPackedEventConditionRowSummary,
cargo_catalog: &[RuntimeCargoCatalogEntry],
) -> RuntimePackedEventConditionRowSummary {
let cargo_entry = row
.recovered_cargo_slot
.and_then(|slot| cargo_catalog.iter().find(|entry| entry.slot_id == slot));
RuntimePackedEventConditionRowSummary {
row_index: row.row_index,
raw_condition_id: row.raw_condition_id,
@ -918,13 +976,26 @@ fn runtime_packed_event_condition_row_summary_from_smp(
semantic_family: row.semantic_family.clone(),
semantic_preview: row.semantic_preview.clone(),
requires_candidate_name_binding: row.requires_candidate_name_binding,
recovered_cargo_slot: row.recovered_cargo_slot,
recovered_cargo_class: row.recovered_cargo_class.clone(),
recovered_cargo_label: cargo_entry
.map(|entry| entry.label.clone())
.or_else(|| row.recovered_cargo_slot.map(default_cargo_slot_label)),
recovered_cargo_supplied_token_stem: cargo_entry
.and_then(|entry| entry.supplied_token_stem.clone()),
recovered_cargo_demanded_token_stem: cargo_entry
.and_then(|entry| entry.demanded_token_stem.clone()),
notes: row.notes.clone(),
}
}
fn runtime_packed_event_grouped_effect_row_summary_from_smp(
row: &crate::SmpLoadedPackedEventGroupedEffectRowSummary,
cargo_catalog: &[RuntimeCargoCatalogEntry],
) -> RuntimePackedEventGroupedEffectRowSummary {
let cargo_entry = row
.recovered_cargo_slot
.and_then(|slot| cargo_catalog.iter().find(|entry| entry.slot_id == slot));
RuntimePackedEventGroupedEffectRowSummary {
group_index: row.group_index,
row_index: row.row_index,
@ -943,12 +1014,25 @@ fn runtime_packed_event_grouped_effect_row_summary_from_smp(
row_shape: row.row_shape.clone(),
semantic_family: row.semantic_family.clone(),
semantic_preview: row.semantic_preview.clone(),
recovered_cargo_slot: row.recovered_cargo_slot,
recovered_cargo_class: row.recovered_cargo_class.clone(),
recovered_cargo_label: cargo_entry
.map(|entry| entry.label.clone())
.or_else(|| row.recovered_cargo_slot.map(default_cargo_slot_label)),
recovered_cargo_supplied_token_stem: cargo_entry
.and_then(|entry| entry.supplied_token_stem.clone()),
recovered_cargo_demanded_token_stem: cargo_entry
.and_then(|entry| entry.demanded_token_stem.clone()),
recovered_locomotive_id: row.recovered_locomotive_id,
locomotive_name: row.locomotive_name.clone(),
notes: row.notes.clone(),
}
}
fn default_cargo_slot_label(slot: u32) -> String {
format!("Cargo Production Slot {slot}")
}
fn smp_packed_record_to_runtime_event_record(
record: &SmpLoadedPackedEventRecordSummary,
company_context: &ImportRuntimeContext,
@ -2251,6 +2335,17 @@ fn determine_packed_event_import_outcome(
{
return "blocked_retire_train_variant".to_string();
}
if record
.standalone_condition_rows
.iter()
.any(|row| row.raw_condition_id >= 0)
{
if record_has_world_state_condition_rows(record) {
return "blocked_unmapped_world_condition".to_string();
} else {
return "blocked_unmapped_ordinary_condition".to_string();
}
}
if record
.grouped_effect_rows
.iter()
@ -2258,19 +2353,7 @@ fn determine_packed_event_import_outcome(
{
return "blocked_unmapped_world_descriptor".to_string();
}
return if record
.standalone_condition_rows
.iter()
.any(|row| row.raw_condition_id >= 0)
{
if record_has_world_state_condition_rows(record) {
"blocked_unmapped_world_condition".to_string()
} else {
"blocked_unmapped_ordinary_condition".to_string()
}
} else {
"blocked_unmapped_real_descriptor".to_string()
};
return "blocked_unmapped_real_descriptor".to_string();
}
if let Some(blocker) = packed_record_condition_scope_import_blocker(record, company_context)
{
@ -2952,6 +3035,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -3717,6 +3801,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: None,
notes: vec![],
@ -3757,6 +3842,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: None,
notes: vec![],
@ -3871,6 +3957,7 @@ mod tests {
},
),
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: Some(crate::SmpLoadedSpecialConditionsTable {
source_kind: "save-fixed-special-conditions-range".to_string(),
table_offset: 0x0d64,
@ -4196,6 +4283,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4311,6 +4399,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4404,6 +4493,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4515,6 +4605,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4599,6 +4690,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4733,6 +4825,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -4975,6 +5068,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5052,6 +5146,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5153,6 +5248,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5227,6 +5323,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5328,6 +5425,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5405,6 +5503,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: Some(save_named_locomotive_table(112)),
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5522,6 +5621,7 @@ mod tests {
name: "Locomotive 112".to_string(),
},
],
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -5548,6 +5648,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5650,6 +5751,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5726,6 +5828,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5802,6 +5905,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: Some(save_named_locomotive_table(112)),
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -5912,6 +6016,7 @@ mod tests {
name: "Locomotive 101".to_string(),
},
],
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -5938,6 +6043,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6033,6 +6139,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6107,6 +6214,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6191,6 +6299,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6294,6 +6403,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -6317,6 +6427,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6464,6 +6575,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6568,6 +6680,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6653,6 +6766,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6759,6 +6873,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6865,6 +6980,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -6961,6 +7077,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7053,6 +7170,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7153,6 +7271,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7244,6 +7363,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7317,6 +7437,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7395,6 +7516,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7478,6 +7600,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7561,6 +7684,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7660,6 +7784,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7750,6 +7875,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7866,6 +7992,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -7995,6 +8122,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8292,6 +8420,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8402,6 +8531,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8575,6 +8705,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8668,6 +8799,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8757,6 +8889,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -8911,6 +9044,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9054,6 +9188,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9144,6 +9279,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9261,6 +9397,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9366,6 +9503,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9474,6 +9612,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -9512,6 +9651,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),
@ -9656,6 +9796,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -9687,6 +9828,7 @@ mod tests {
candidate_availability_table: None,
named_locomotive_availability_table: None,
locomotive_catalog: None,
cargo_catalog: None,
special_conditions_table: None,
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
source_kind: "packed-event-runtime-collection".to_string(),

View file

@ -35,29 +35,30 @@ pub use pk4::{
extract_pk4_entry_bytes, extract_pk4_entry_file, inspect_pk4_bytes, inspect_pk4_file,
};
pub use runtime::{
RuntimeCompany, RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind,
RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess,
RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeConditionComparator,
RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry,
RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary,
RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary,
RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary,
RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePlayerConditionTestScope,
RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState,
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric,
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldRestoreState,
RuntimeCargoCatalogEntry, RuntimeCompany, RuntimeCompanyConditionTestScope,
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget,
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric,
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain,
RuntimeWorldRestoreState,
};
pub use smp::{
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,
SmpAlignedRuntimeRuleBandProbe, SmpAsciiPreview, SmpClassicPackedProfileBlock,
SmpClassicRehydrateProfileProbe, SmpContainerProfile, SmpEarlyContentProbe,
SmpHeaderVariantProbe, SmpInspectionReport, SmpKnownTagHit,
SmpLoadedCandidateAvailabilityTable, SmpLoadedEventRuntimeCollectionSummary,
SmpLoadedNamedLocomotiveAvailabilityTable, SmpLoadedPackedEventCompactControlSummary,
SmpLoadedPackedEventConditionRowSummary, SmpLoadedPackedEventGroupedEffectRowSummary,
SmpLoadedPackedEventNegativeSentinelScopeSummary, SmpLoadedPackedEventRecordSummary,
SmpLoadedPackedEventTextBandSummary, SmpLoadedProfile, SmpLoadedSaveSlice,
SmpLoadedSpecialConditionsTable, SmpLocomotivePolicyFieldObservation,
SmpLoadedCandidateAvailabilityTable, SmpLoadedCargoCatalog, SmpLoadedCargoCatalogEntry,
SmpLoadedEventRuntimeCollectionSummary, SmpLoadedNamedLocomotiveAvailabilityTable,
SmpLoadedPackedEventCompactControlSummary, SmpLoadedPackedEventConditionRowSummary,
SmpLoadedPackedEventGroupedEffectRowSummary, SmpLoadedPackedEventNegativeSentinelScopeSummary,
SmpLoadedPackedEventRecordSummary, SmpLoadedPackedEventTextBandSummary, SmpLoadedProfile,
SmpLoadedSaveSlice, SmpLoadedSpecialConditionsTable, SmpLocomotivePolicyFieldObservation,
SmpLocomotivePolicyFloatAlignmentCandidate, SmpLocomotivePolicyNeighborhoodProbe,
SmpPackedProfileWordLane, SmpPostSpecialConditionsScalarLane,
SmpPostSpecialConditionsScalarProbe, SmpPostTextFieldNeighborhoodProbe,

View file

@ -98,6 +98,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),

View file

@ -113,6 +113,16 @@ pub struct RuntimeLocomotiveCatalogEntry {
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RuntimeCargoCatalogEntry {
pub slot_id: u32,
pub label: String,
#[serde(default)]
pub supplied_token_stem: Option<String>,
#[serde(default)]
pub demanded_token_stem: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum RuntimeCompanyTarget {
@ -533,6 +543,16 @@ pub struct RuntimePackedEventConditionRowSummary {
#[serde(default)]
pub requires_candidate_name_binding: bool,
#[serde(default)]
pub recovered_cargo_slot: Option<u32>,
#[serde(default)]
pub recovered_cargo_class: Option<String>,
#[serde(default)]
pub recovered_cargo_label: Option<String>,
#[serde(default)]
pub recovered_cargo_supplied_token_stem: Option<String>,
#[serde(default)]
pub recovered_cargo_demanded_token_stem: Option<String>,
#[serde(default)]
pub notes: Vec<String>,
}
@ -561,6 +581,16 @@ pub struct RuntimePackedEventGroupedEffectRowSummary {
#[serde(default)]
pub semantic_preview: Option<String>,
#[serde(default)]
pub recovered_cargo_slot: Option<u32>,
#[serde(default)]
pub recovered_cargo_class: Option<String>,
#[serde(default)]
pub recovered_cargo_label: Option<String>,
#[serde(default)]
pub recovered_cargo_supplied_token_stem: Option<String>,
#[serde(default)]
pub recovered_cargo_demanded_token_stem: Option<String>,
#[serde(default)]
pub recovered_locomotive_id: Option<u32>,
#[serde(default)]
pub locomotive_name: Option<String>,
@ -684,6 +714,8 @@ pub struct RuntimeState {
#[serde(default)]
pub locomotive_catalog: Vec<RuntimeLocomotiveCatalogEntry>,
#[serde(default)]
pub cargo_catalog: Vec<RuntimeCargoCatalogEntry>,
#[serde(default)]
pub territories: Vec<RuntimeTerritory>,
#[serde(default)]
pub company_territory_track_piece_counts: Vec<RuntimeCompanyTerritoryTrackPieceCount>,
@ -837,6 +869,28 @@ impl RuntimeState {
));
}
}
let mut seen_cargo_slots = BTreeSet::new();
let mut seen_cargo_labels = BTreeSet::new();
for entry in &self.cargo_catalog {
if !(1..=11).contains(&entry.slot_id) {
return Err(format!(
"cargo_catalog entry has out-of-range slot_id {}",
entry.slot_id
));
}
if !seen_cargo_slots.insert(entry.slot_id) {
return Err(format!("duplicate cargo_catalog.slot_id {}", entry.slot_id));
}
if entry.label.trim().is_empty() {
return Err(format!(
"cargo_catalog entry {} has an empty label",
entry.slot_id
));
}
if !seen_cargo_labels.insert(entry.label.clone()) {
return Err(format!("duplicate cargo_catalog.label {:?}", entry.label));
}
}
for entry in &self.company_territory_track_piece_counts {
if !seen_company_ids.contains(&entry.company_id) {
return Err(format!(
@ -1550,6 +1604,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1610,6 +1665,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1655,6 +1711,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1713,6 +1770,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1771,6 +1829,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1880,6 +1939,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1925,6 +1985,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1987,6 +2048,7 @@ mod tests {
},
],
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -2039,6 +2101,7 @@ mod tests {
retired: false,
}],
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -2091,6 +2154,7 @@ mod tests {
retired: false,
}],
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: vec![RuntimeTerritory {
territory_id: 1,
name: Some("Appalachia".to_string()),
@ -2147,6 +2211,7 @@ mod tests {
retired: true,
}],
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -2192,6 +2257,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: vec![RuntimeTerritory {
territory_id: 7,
name: Some("Appalachia".to_string()),
@ -2250,6 +2316,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: vec![RuntimeTerritory {
territory_id: 7,
name: Some("Appalachia".to_string()),
@ -2302,6 +2369,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: vec![RuntimeTerritory {
territory_id: 7,
name: Some("Appalachia".to_string()),

View file

@ -1625,6 +1625,33 @@ pub struct SmpLoadedLocomotiveCatalog {
pub entries: Vec<SmpLoadedLocomotiveCatalogEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCargoCatalogEntry {
pub slot_id: u32,
pub label: String,
pub book_index: usize,
pub max_annual_production_word: u32,
pub mode_word: u32,
pub runtime_import_branch_kind: String,
pub annual_amount_word: u32,
pub supplied_cargo_token_word: u32,
#[serde(default)]
pub supplied_cargo_token_probable_high16_ascii_stem: Option<String>,
pub demanded_cargo_token_word: u32,
#[serde(default)]
pub demanded_cargo_token_probable_high16_ascii_stem: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedCargoCatalog {
pub source_kind: String,
pub semantic_family: String,
#[serde(default)]
pub root_offset: Option<usize>,
pub observed_entry_count: usize,
pub entries: Vec<SmpLoadedCargoCatalogEntry>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SmpLoadedSpecialConditionsTable {
pub source_kind: String,
@ -1808,6 +1835,8 @@ pub struct SmpLoadedSaveSlice {
pub named_locomotive_availability_table: Option<SmpLoadedNamedLocomotiveAvailabilityTable>,
#[serde(default)]
pub locomotive_catalog: Option<SmpLoadedLocomotiveCatalog>,
#[serde(default)]
pub cargo_catalog: Option<SmpLoadedCargoCatalog>,
pub special_conditions_table: Option<SmpLoadedSpecialConditionsTable>,
pub event_runtime_collection: Option<SmpLoadedEventRuntimeCollectionSummary>,
pub notes: Vec<String>,
@ -1972,6 +2001,10 @@ pub fn load_save_slice_from_report(
let locomotive_catalog = named_locomotive_availability_table
.as_ref()
.and_then(derive_locomotive_catalog_from_named_availability_table);
let cargo_catalog = report
.recipe_book_summary_probe
.as_ref()
.and_then(derive_cargo_catalog_from_recipe_book_probe);
let special_conditions_table =
report
.special_conditions_probe
@ -1996,6 +2029,7 @@ pub fn load_save_slice_from_report(
candidate_availability_table,
named_locomotive_availability_table,
locomotive_catalog,
cargo_catalog,
special_conditions_table,
event_runtime_collection: report.event_runtime_collection_summary.clone(),
notes: summary.notes.clone(),
@ -2028,6 +2062,57 @@ fn derive_locomotive_catalog_from_named_availability_table(
})
}
fn derive_cargo_catalog_from_recipe_book_probe(
probe: &SmpRecipeBookSummaryProbe,
) -> Option<SmpLoadedCargoCatalog> {
if probe.books.is_empty() {
return None;
}
let entries = probe
.books
.iter()
.filter(|book| book.book_index < 11)
.filter_map(|book| {
let line = book
.lines
.iter()
.find(|line| line.imports_to_runtime_descriptor)
.or_else(|| book.lines.first())?;
let slot_id = (book.book_index + 1) as u32;
Some(SmpLoadedCargoCatalogEntry {
slot_id,
label: format!("Cargo Production Slot {slot_id}"),
book_index: book.book_index,
max_annual_production_word: book.max_annual_production_word,
mode_word: line.mode_word,
runtime_import_branch_kind: line.runtime_import_branch_kind.clone(),
annual_amount_word: line.annual_amount_word,
supplied_cargo_token_word: line.supplied_cargo_token_word,
supplied_cargo_token_probable_high16_ascii_stem: line
.supplied_cargo_token_probable_high16_ascii_stem
.clone(),
demanded_cargo_token_word: line.demanded_cargo_token_word,
demanded_cargo_token_probable_high16_ascii_stem: line
.demanded_cargo_token_probable_high16_ascii_stem
.clone(),
})
})
.collect::<Vec<_>>();
if entries.is_empty() {
return None;
}
Some(SmpLoadedCargoCatalog {
source_kind: format!("{}-slot-catalog", probe.source_kind),
semantic_family: "scenario-save-derived-cargo-catalog".to_string(),
root_offset: Some(probe.root_offset),
observed_entry_count: entries.len(),
entries,
})
}
fn parse_event_runtime_collection_summary(
bytes: &[u8],
container_profile: Option<&SmpContainerProfile>,

View file

@ -1249,6 +1249,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),

View file

@ -37,6 +37,7 @@ pub struct RuntimeSummary {
pub active_train_count: usize,
pub retired_train_count: usize,
pub locomotive_catalog_count: usize,
pub cargo_catalog_count: usize,
pub territory_count: usize,
pub company_territory_track_count: usize,
pub packed_event_collection_present: bool,
@ -172,6 +173,7 @@ impl RuntimeSummary {
active_train_count: state.trains.iter().filter(|train| train.active).count(),
retired_train_count: state.trains.iter().filter(|train| train.retired).count(),
locomotive_catalog_count: state.locomotive_catalog.len(),
cargo_catalog_count: state.cargo_catalog.len(),
territory_count: state.territories.len(),
company_territory_track_count: state.company_territory_track_piece_counts.len(),
packed_event_collection_present: state.packed_event_collection.is_some(),
@ -675,6 +677,7 @@ mod tests {
name: "Locomotive 112".to_string(),
},
],
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -917,6 +920,7 @@ mod tests {
name: "Locomotive 112".to_string(),
},
],
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -963,6 +967,7 @@ mod tests {
name: "Locomotive 112".to_string(),
},
],
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1006,6 +1011,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1049,6 +1055,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1087,6 +1094,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),
@ -1194,6 +1202,7 @@ mod tests {
selected_player_id: None,
trains: Vec::new(),
locomotive_catalog: Vec::new(),
cargo_catalog: Vec::new(),
territories: Vec::new(),
company_territory_track_piece_counts: Vec::new(),
company_territory_access: Vec::new(),

View file

@ -138,12 +138,16 @@ The highest-value next passes are now:
- cargo-production `230..240` and territory-access-cost `453` now execute too through minimal
world-side scalar landing surfaces: slot-indexed `cargo_production_overrides` and
`world_restore.territory_access_cost`
- recipe-book probing now derives a save-native `cargo_catalog` too, so save-slice documents carry
stable cargo slot labels and token-stem evidence into runtime state without requiring a separate
cargo simulation layer
- world-scalar ordinary-condition coverage now matches those runtime surfaces too: checked-in
metadata lowers named locomotive availability, named locomotive cost, named cargo-production
slot thresholds, aggregate cargo production, limited-track-building-amount, and
territory-access-cost rows into explicit runtime condition gates
- the remaining world-scalar condition frontier is now narrow and explicit: unsupported families
such as `All Factory Production` stay parity-only on `blocked_unmapped_world_condition`
such as `All Factory Production` stay parity-only on `blocked_unmapped_world_condition`; the
remaining cargo frontier is slot-to-class classification, not save/import plumbing
- keep in mind that the current local `.gms` corpus still exports with no packed event collection,
so real descriptor mapping needs to stay plumbing-first until better captures exist
- use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution

View file

@ -97,12 +97,16 @@ Implemented today:
- the remaining recovered scalar world families now execute as well: cargo-production `230..240`
rows lower into slot-indexed `cargo_production_overrides`, and territory-access-cost descriptor
`453` lowers into `world_restore.territory_access_cost`
- cargo slot identity is now save-native as well: the recipe-book probe derives a bounded
`cargo_catalog` into save-slice documents and runtime state, so cargo descriptors and
`%1 Production` conditions can expose stable slot metadata without a live cargo simulation layer
- world-scalar ordinary-condition coverage now aligns with those runtime surfaces too: checked-in
metadata lowers named locomotive availability, named locomotive cost, named cargo-production
slot thresholds, aggregate cargo production, limited-track-building-amount, and
territory-access-cost rows into explicit runtime condition gates
- the remaining world-side condition frontier is now narrower and more honest: unsupported scalar
families such as `All Factory Production` stay visible on `blocked_unmapped_world_condition`
families such as `All Factory Production` stay visible on `blocked_unmapped_world_condition`;
the remaining cargo frontier is slot classification rather than missing save/import context
instead of falling back to generic placeholder ids
That means the next implementation work is breadth, not bootstrap. The recommended next slice is

View file

@ -0,0 +1,44 @@
{
"format_version": 1,
"fixture_id": "packed-event-cargo-catalog-save-slice-fixture",
"source": {
"kind": "captured-runtime",
"description": "Fixture proving recipe-book-derived cargo catalog context imports into runtime state even without executable event records."
},
"state_save_slice_path": "packed-event-cargo-catalog-save-slice.json",
"commands": [
{
"kind": "step_count",
"steps": 1
}
],
"expected_summary": {
"calendar": {
"year": 1830,
"month_slot": 0,
"phase_slot": 0,
"tick_slot": 1
},
"calendar_projection_is_placeholder": true,
"world_flag_count": 8,
"cargo_catalog_count": 11,
"packed_event_collection_present": false,
"event_runtime_record_count": 0
},
"expected_state_fragment": {
"cargo_catalog": [
{
"slot_id": 1,
"label": "Cargo Production Slot 1"
},
{
"slot_id": 2,
"label": "Cargo Production Slot 2"
}
],
"metadata": {
"save_slice.cargo_catalog_source_kind": "recipe-book-summary-slot-catalog",
"save_slice.cargo_catalog_entry_count": "11"
}
}
}

View file

@ -0,0 +1,48 @@
{
"format_version": 1,
"save_slice_id": "packed-event-cargo-catalog-save-slice",
"source": {
"description": "Tracked save-slice document proving save-native cargo catalog export/import without executable packed-event commands.",
"original_save_filename": "captured-cargo-catalog.gms",
"original_save_sha256": "cargo-catalog-sample-sha256",
"notes": [
"tracked as JSON save-slice document rather than raw .smp",
"pins the save-native recipe-book-derived cargo catalog surface independently of event execution"
]
},
"save_slice": {
"file_extension_hint": "gms",
"container_profile_family": "rt3-classic-save-container-v1",
"mechanism_family": "classic-save-rehydrate-v1",
"mechanism_confidence": "grounded",
"trailer_family": null,
"bridge_family": null,
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"cargo_catalog": {
"source_kind": "recipe-book-summary-slot-catalog",
"semantic_family": "scenario-save-derived-cargo-catalog",
"root_offset": 4071,
"observed_entry_count": 11,
"entries": [
{ "slot_id": 1, "label": "Cargo Production Slot 1", "book_index": 0, "max_annual_production_word": 0, "mode_word": 1114112, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 2, "label": "Cargo Production Slot 2", "book_index": 1, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 3, "label": "Cargo Production Slot 3", "book_index": 2, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 4, "label": "Cargo Production Slot 4", "book_index": 3, "max_annual_production_word": 0, "mode_word": 1245184, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 5, "label": "Cargo Production Slot 5", "book_index": 4, "max_annual_production_word": 0, "mode_word": 1572864, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 6, "label": "Cargo Production Slot 6", "book_index": 5, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 7, "label": "Cargo Production Slot 7", "book_index": 6, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 8, "label": "Cargo Production Slot 8", "book_index": 7, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 9, "label": "Cargo Production Slot 9", "book_index": 8, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 10, "label": "Cargo Production Slot 10", "book_index": 9, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 11, "label": "Cargo Production Slot 11", "book_index": 10, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null }
]
},
"special_conditions_table": null,
"event_runtime_collection": null,
"notes": [
"cargo catalog only sample"
]
}
}

View file

@ -21,7 +21,7 @@
},
"calendar_projection_source": "base-snapshot-preserved",
"calendar_projection_is_placeholder": false,
"world_flag_count": 9,
"world_flag_count": 10,
"company_count": 1,
"packed_event_collection_present": true,
"packed_event_record_count": 2,

View file

@ -26,6 +26,7 @@
"packed_event_imported_runtime_record_count": 2,
"packed_event_parity_only_record_count": 3,
"packed_event_unsupported_record_count": 0,
"cargo_catalog_count": 11,
"packed_event_blocked_missing_locomotive_catalog_context_count": 0,
"packed_event_blocked_missing_condition_context_count": 0,
"packed_event_blocked_territory_condition_scope_count": 0,
@ -52,6 +53,8 @@
{
"descriptor_id": 230,
"descriptor_label": "Cargo Production Slot 1",
"recovered_cargo_slot": 1,
"recovered_cargo_label": "Cargo Production Slot 1",
"target_mask_bits": 8,
"parameter_family": "cargo_production_scalar",
"semantic_family": "scalar_assignment",

View file

@ -20,6 +20,25 @@
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"cargo_catalog": {
"source_kind": "recipe-book-summary-slot-catalog",
"semantic_family": "scenario-save-derived-cargo-catalog",
"root_offset": 4071,
"observed_entry_count": 11,
"entries": [
{ "slot_id": 1, "label": "Cargo Production Slot 1", "book_index": 0, "max_annual_production_word": 0, "mode_word": 1114112, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 2, "label": "Cargo Production Slot 2", "book_index": 1, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 3, "label": "Cargo Production Slot 3", "book_index": 2, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 4, "label": "Cargo Production Slot 4", "book_index": 3, "max_annual_production_word": 0, "mode_word": 1245184, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 5, "label": "Cargo Production Slot 5", "book_index": 4, "max_annual_production_word": 0, "mode_word": 1572864, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 6, "label": "Cargo Production Slot 6", "book_index": 5, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 7, "label": "Cargo Production Slot 7", "book_index": 6, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 8, "label": "Cargo Production Slot 8", "book_index": 7, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 9, "label": "Cargo Production Slot 9", "book_index": 8, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 10, "label": "Cargo Production Slot 10", "book_index": 9, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 11, "label": "Cargo Production Slot 11", "book_index": 10, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null }
]
},
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",

View file

@ -18,17 +18,24 @@
"packed_event_decoded_record_count": 1,
"packed_event_imported_runtime_record_count": 0,
"packed_event_parity_only_record_count": 1,
"packed_event_blocked_unmapped_world_descriptor_count": 1,
"packed_event_blocked_unmapped_world_condition_count": 1,
"cargo_catalog_count": 11,
"event_runtime_record_count": 0,
"world_flag_count": 7,
"world_flag_count": 8,
"total_event_record_service_count": 0,
"total_trigger_dispatch_count": 1
},
"expected_state_fragment": {
"cargo_catalog": [
{
"slot_id": 1,
"label": "Cargo Production Slot 1"
}
],
"packed_event_collection": {
"records": [
{
"import_outcome": "blocked_unmapped_world_descriptor",
"import_outcome": "blocked_unmapped_world_condition",
"standalone_condition_rows": [
{
"raw_condition_id": 2419,

View file

@ -20,6 +20,25 @@
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"cargo_catalog": {
"source_kind": "recipe-book-summary-slot-catalog",
"semantic_family": "scenario-save-derived-cargo-catalog",
"root_offset": 4071,
"observed_entry_count": 11,
"entries": [
{ "slot_id": 1, "label": "Cargo Production Slot 1", "book_index": 0, "max_annual_production_word": 0, "mode_word": 1114112, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 2, "label": "Cargo Production Slot 2", "book_index": 1, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 3, "label": "Cargo Production Slot 3", "book_index": 2, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 4, "label": "Cargo Production Slot 4", "book_index": 3, "max_annual_production_word": 0, "mode_word": 1245184, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 5, "label": "Cargo Production Slot 5", "book_index": 4, "max_annual_production_word": 0, "mode_word": 1572864, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 6, "label": "Cargo Production Slot 6", "book_index": 5, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 7, "label": "Cargo Production Slot 7", "book_index": 6, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 8, "label": "Cargo Production Slot 8", "book_index": 7, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 9, "label": "Cargo Production Slot 9", "book_index": 8, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 10, "label": "Cargo Production Slot 10", "book_index": 9, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 11, "label": "Cargo Production Slot 11", "book_index": 10, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null }
]
},
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",

View file

@ -22,13 +22,14 @@
"packed_event_decoded_record_count": 2,
"packed_event_imported_runtime_record_count": 2,
"event_runtime_record_count": 2,
"cargo_catalog_count": 11,
"named_locomotive_availability_count": 1,
"zero_named_locomotive_availability_count": 0,
"named_locomotive_cost_count": 1,
"cargo_production_override_count": 1,
"world_restore_limited_track_building_amount": 18,
"world_restore_territory_access_cost": 750000,
"world_flag_count": 8,
"world_flag_count": 9,
"total_event_record_service_count": 2,
"total_trigger_dispatch_count": 2
},
@ -49,6 +50,12 @@
"cargo_production_overrides": {
"1": 125
},
"cargo_catalog": [
{
"slot_id": 1,
"label": "Cargo Production Slot 1"
}
],
"packed_event_collection": {
"records": [
{

View file

@ -20,6 +20,25 @@
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"cargo_catalog": {
"source_kind": "recipe-book-summary-slot-catalog",
"semantic_family": "scenario-save-derived-cargo-catalog",
"root_offset": 4071,
"observed_entry_count": 11,
"entries": [
{ "slot_id": 1, "label": "Cargo Production Slot 1", "book_index": 0, "max_annual_production_word": 0, "mode_word": 1114112, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 2, "label": "Cargo Production Slot 2", "book_index": 1, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 3, "label": "Cargo Production Slot 3", "book_index": 2, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 4, "label": "Cargo Production Slot 4", "book_index": 3, "max_annual_production_word": 0, "mode_word": 1245184, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 5, "label": "Cargo Production Slot 5", "book_index": 4, "max_annual_production_word": 0, "mode_word": 1572864, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 6, "label": "Cargo Production Slot 6", "book_index": 5, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 7, "label": "Cargo Production Slot 7", "book_index": 6, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 8, "label": "Cargo Production Slot 8", "book_index": 7, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 9, "label": "Cargo Production Slot 9", "book_index": 8, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 10, "label": "Cargo Production Slot 10", "book_index": 9, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 11, "label": "Cargo Production Slot 11", "book_index": 10, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null }
]
},
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",

View file

@ -25,6 +25,7 @@
"packed_event_decoded_record_count": 1,
"packed_event_imported_runtime_record_count": 1,
"packed_event_parity_only_record_count": 1,
"cargo_catalog_count": 11,
"packed_event_blocked_unmapped_world_descriptor_count": 0,
"event_runtime_record_count": 1,
"cargo_production_override_count": 1,

View file

@ -20,6 +20,25 @@
"profile": null,
"candidate_availability_table": null,
"named_locomotive_availability_table": null,
"cargo_catalog": {
"source_kind": "recipe-book-summary-slot-catalog",
"semantic_family": "scenario-save-derived-cargo-catalog",
"root_offset": 4071,
"observed_entry_count": 11,
"entries": [
{ "slot_id": 1, "label": "Cargo Production Slot 1", "book_index": 0, "max_annual_production_word": 0, "mode_word": 1114112, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 2, "label": "Cargo Production Slot 2", "book_index": 1, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 3, "label": "Cargo Production Slot 3", "book_index": 2, "max_annual_production_word": 0, "mode_word": 720896, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 4, "label": "Cargo Production Slot 4", "book_index": 3, "max_annual_production_word": 0, "mode_word": 1245184, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 5, "label": "Cargo Production Slot 5", "book_index": 4, "max_annual_production_word": 0, "mode_word": 1572864, "runtime_import_branch_kind": "nonzero-supply-branch", "annual_amount_word": 0, "supplied_cargo_token_word": 16544, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 6, "label": "Cargo Production Slot 6", "book_index": 5, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 7, "label": "Cargo Production Slot 7", "book_index": 6, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 8, "label": "Cargo Production Slot 8", "book_index": 7, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 9, "label": "Cargo Production Slot 9", "book_index": 8, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 10, "label": "Cargo Production Slot 10", "book_index": 9, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null },
{ "slot_id": 11, "label": "Cargo Production Slot 11", "book_index": 10, "max_annual_production_word": 0, "mode_word": 0, "runtime_import_branch_kind": "zero-mode-skipped", "annual_amount_word": 0, "supplied_cargo_token_word": 0, "supplied_cargo_token_probable_high16_ascii_stem": null, "demanded_cargo_token_word": 0, "demanded_cargo_token_probable_high16_ascii_stem": null }
]
},
"special_conditions_table": null,
"event_runtime_collection": {
"source_kind": "packed-event-runtime-collection",