Extend cargo selector and save-world analysis surfaces
This commit is contained in:
parent
cebcb8ad33
commit
6b8f849731
11 changed files with 639 additions and 26 deletions
13
README.md
13
README.md
|
|
@ -33,7 +33,9 @@ still does not reconstruct those company/chairman collections automatically, but
|
|||
reconstruct selection-only company/chairman context from the fixed save-side `0x32c8` world block.
|
||||
Those raw selected ids can flow through save-slice export/import and override overlay-backed base
|
||||
selection even while the full raw rosters remain absent, and a tracked overlay fixture now pins
|
||||
that selection-only override path explicitly. A checked-in
|
||||
that selection-only override path explicitly. The same fixed block now also exports the grounded
|
||||
campaign override byte plus the raw chairman slot selector and role-gate bytes as analysis-only
|
||||
save fields. A checked-in
|
||||
`EventEffects` export now exists too in
|
||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer now
|
||||
exists beside it in `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`. Recovered
|
||||
|
|
@ -45,7 +47,8 @@ company-governance scalar effect surface:
|
|||
descriptor `56` `Credit Rating` and descriptor `57` `Prime Rate` execute from ordinary real packed
|
||||
rows, while adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices`
|
||||
and `58` `Merger Premium` now land on explicit shell-owned parity instead of anonymous unmapped
|
||||
descriptor residue, and tracked shell-owned fixtures now pin both finance rows explicitly. The
|
||||
descriptor residue, and tracked shell-owned fixtures now pin finance, scenario-outcome, and
|
||||
control-transfer shell rows explicitly. The
|
||||
recovered whole-game scalar economy/performance strip `59..104` now has a
|
||||
bounded runtime landing surface too: representative descriptors import into
|
||||
`RuntimeState.world_scalar_overrides` through stable normalized keys such as
|
||||
|
|
@ -68,8 +71,10 @@ offline cargo-source inspector now pushes that groundwork further in rehosted co
|
|||
`artifacts/exports/rt3-1.06/economy-cargo-sources.json` report parses both `CargoTypes` and the
|
||||
`Cargo106.PK4` `cargoSkin` descriptors, normalizes localized `~####Name` tokens into visible
|
||||
names, builds a merged live cargo registry, and derives an exact named cargo-production selector
|
||||
from the checked-in bindings. It also shows that the current 1.06 visible-name union is `80`, not
|
||||
`71`, so source recovery alone still does not prove the live price-selector ordering. The
|
||||
from the checked-in bindings. Dedicated CLI inspector commands now expose that production selector
|
||||
and the unresolved price-selector candidate registry directly. The same report still shows that the
|
||||
current 1.06 visible-name union is `80`, not `71`, so source recovery alone still does not prove
|
||||
the live price-selector ordering. The
|
||||
add-building strip `503..519` is now explicitly classified as recovered
|
||||
shell-owned descriptor parity rather than generic unresolved residue. The first grounded
|
||||
condition-side unlock now exists for negative-sentinel `raw_condition_id = -1` company scopes, and
|
||||
|
|
|
|||
|
|
@ -972,6 +972,39 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"price_selector_candidate_excess_count": 9,
|
||||
"price_selector_candidate_only_visible_names": [
|
||||
"Beer",
|
||||
"Candidates",
|
||||
"China",
|
||||
"Containers",
|
||||
"Detergents",
|
||||
"Deuterium",
|
||||
"Energy",
|
||||
"Fish",
|
||||
"Food",
|
||||
"Glass",
|
||||
"Gravel",
|
||||
"Money",
|
||||
"Newspaper",
|
||||
"Paint",
|
||||
"Perfume",
|
||||
"Potash",
|
||||
"Pottery",
|
||||
"Prisoners",
|
||||
"Rock",
|
||||
"Salt",
|
||||
"Sand",
|
||||
"Spaceships",
|
||||
"Syrup",
|
||||
"Tea",
|
||||
"Tin",
|
||||
"Tobacco",
|
||||
"Tools",
|
||||
"Valuables",
|
||||
"Wine",
|
||||
"Wire"
|
||||
],
|
||||
"production_selector": {
|
||||
"selector_kind": "named_cargo_production",
|
||||
"exact_resolution": true,
|
||||
|
|
|
|||
|
|
@ -18,16 +18,17 @@ use rrt_model::{
|
|||
};
|
||||
use rrt_runtime::{
|
||||
CAMPAIGN_SCENARIO_COUNT, CampaignExeInspectionReport, CargoEconomySourceReport,
|
||||
CargoSkinInspectionReport, CargoTypeInspectionReport, OBSERVED_CAMPAIGN_SCENARIO_NAMES,
|
||||
OVERLAY_IMPORT_DOCUMENT_FORMAT_VERSION, Pk4ExtractionReport, Pk4InspectionReport,
|
||||
RuntimeOverlayImportDocument, RuntimeOverlayImportDocumentSource, RuntimeSaveSliceDocument,
|
||||
RuntimeSaveSliceDocumentSource, RuntimeSnapshotDocument, RuntimeSnapshotSource, RuntimeSummary,
|
||||
SAVE_SLICE_DOCUMENT_FORMAT_VERSION, SNAPSHOT_FORMAT_VERSION, SmpClassicPackedProfileBlock,
|
||||
SmpInspectionReport, SmpLoadedSaveSlice, SmpRt3105PackedProfileBlock, SmpSaveLoadSummary,
|
||||
WinInspectionReport, execute_step_command, extract_pk4_entry_file, inspect_campaign_exe_file,
|
||||
inspect_cargo_economy_sources_with_bindings, inspect_cargo_skin_pk4, inspect_cargo_types_dir,
|
||||
inspect_pk4_file, inspect_smp_file, inspect_win_file, load_runtime_snapshot_document,
|
||||
load_runtime_state_import, load_save_slice_file, project_save_slice_to_runtime_state_import,
|
||||
CargoSelectorReport, CargoSkinInspectionReport, CargoTypeInspectionReport,
|
||||
OBSERVED_CAMPAIGN_SCENARIO_NAMES, OVERLAY_IMPORT_DOCUMENT_FORMAT_VERSION, Pk4ExtractionReport,
|
||||
Pk4InspectionReport, RuntimeOverlayImportDocument, RuntimeOverlayImportDocumentSource,
|
||||
RuntimeSaveSliceDocument, RuntimeSaveSliceDocumentSource, RuntimeSnapshotDocument,
|
||||
RuntimeSnapshotSource, RuntimeSummary, SAVE_SLICE_DOCUMENT_FORMAT_VERSION,
|
||||
SNAPSHOT_FORMAT_VERSION, SmpClassicPackedProfileBlock, SmpInspectionReport, SmpLoadedSaveSlice,
|
||||
SmpRt3105PackedProfileBlock, SmpSaveLoadSummary, WinInspectionReport, execute_step_command,
|
||||
extract_pk4_entry_file, inspect_campaign_exe_file, inspect_cargo_economy_sources_with_bindings,
|
||||
inspect_cargo_skin_pk4, inspect_cargo_types_dir, inspect_pk4_file, inspect_smp_file,
|
||||
inspect_win_file, load_runtime_snapshot_document, load_runtime_state_import,
|
||||
load_save_slice_file, project_save_slice_to_runtime_state_import,
|
||||
save_runtime_overlay_import_document, save_runtime_save_slice_document,
|
||||
save_runtime_snapshot_document, validate_runtime_snapshot_document,
|
||||
};
|
||||
|
|
@ -151,6 +152,14 @@ enum Command {
|
|||
cargo_types_dir: PathBuf,
|
||||
cargo_skin_pk4_path: PathBuf,
|
||||
},
|
||||
RuntimeInspectCargoProductionSelector {
|
||||
cargo_types_dir: PathBuf,
|
||||
cargo_skin_pk4_path: PathBuf,
|
||||
},
|
||||
RuntimeInspectCargoPriceSelector {
|
||||
cargo_types_dir: PathBuf,
|
||||
cargo_skin_pk4_path: PathBuf,
|
||||
},
|
||||
RuntimeInspectWin {
|
||||
win_path: PathBuf,
|
||||
},
|
||||
|
|
@ -303,6 +312,13 @@ struct RuntimeCargoEconomyInspectionOutput {
|
|||
inspection: CargoEconomySourceReport,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RuntimeCargoSelectorInspectionOutput {
|
||||
cargo_types_dir: String,
|
||||
cargo_skin_pk4_path: String,
|
||||
selector: CargoSelectorReport,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RuntimeWinInspectionOutput {
|
||||
path: String,
|
||||
|
|
@ -860,6 +876,18 @@ fn real_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
} => {
|
||||
run_runtime_inspect_cargo_economy_sources(&cargo_types_dir, &cargo_skin_pk4_path)?;
|
||||
}
|
||||
Command::RuntimeInspectCargoProductionSelector {
|
||||
cargo_types_dir,
|
||||
cargo_skin_pk4_path,
|
||||
} => {
|
||||
run_runtime_inspect_cargo_production_selector(&cargo_types_dir, &cargo_skin_pk4_path)?;
|
||||
}
|
||||
Command::RuntimeInspectCargoPriceSelector {
|
||||
cargo_types_dir,
|
||||
cargo_skin_pk4_path,
|
||||
} => {
|
||||
run_runtime_inspect_cargo_price_selector(&cargo_types_dir, &cargo_skin_pk4_path)?;
|
||||
}
|
||||
Command::RuntimeInspectWin { win_path } => {
|
||||
run_runtime_inspect_win(&win_path)?;
|
||||
}
|
||||
|
|
@ -1060,6 +1088,22 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
|
|||
cargo_skin_pk4_path: PathBuf::from(cargo_skin_pk4_path),
|
||||
})
|
||||
}
|
||||
[command, subcommand, cargo_types_dir, cargo_skin_pk4_path]
|
||||
if command == "runtime" && subcommand == "inspect-cargo-production-selector" =>
|
||||
{
|
||||
Ok(Command::RuntimeInspectCargoProductionSelector {
|
||||
cargo_types_dir: PathBuf::from(cargo_types_dir),
|
||||
cargo_skin_pk4_path: PathBuf::from(cargo_skin_pk4_path),
|
||||
})
|
||||
}
|
||||
[command, subcommand, cargo_types_dir, cargo_skin_pk4_path]
|
||||
if command == "runtime" && subcommand == "inspect-cargo-price-selector" =>
|
||||
{
|
||||
Ok(Command::RuntimeInspectCargoPriceSelector {
|
||||
cargo_types_dir: PathBuf::from(cargo_types_dir),
|
||||
cargo_skin_pk4_path: PathBuf::from(cargo_skin_pk4_path),
|
||||
})
|
||||
}
|
||||
[command, subcommand, path] if command == "runtime" && subcommand == "inspect-win" => {
|
||||
Ok(Command::RuntimeInspectWin {
|
||||
win_path: PathBuf::from(path),
|
||||
|
|
@ -1195,7 +1239,7 @@ fn parse_command() -> Result<Command, Box<dyn std::error::Error>> {
|
|||
})
|
||||
}
|
||||
_ => Err(
|
||||
"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 import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime import-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-cargo-skins <Cargo106.PK4> | runtime inspect-cargo-economy-sources <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-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>]"
|
||||
"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 import-state <input.json> <snapshot.json> | runtime inspect-smp <file.smp> | runtime summarize-save-load <file.smp> | runtime load-save-slice <file.smp> | runtime import-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-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-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>]"
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
|
|
@ -1598,6 +1642,49 @@ fn run_runtime_inspect_cargo_economy_sources(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn run_runtime_inspect_cargo_production_selector(
|
||||
cargo_types_dir: &Path,
|
||||
cargo_skin_pk4_path: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let cargo_bindings_path =
|
||||
Path::new("artifacts/exports/rt3-1.06/event-effects-cargo-bindings.json");
|
||||
let inspection = inspect_cargo_economy_sources_with_bindings(
|
||||
cargo_types_dir,
|
||||
cargo_skin_pk4_path,
|
||||
Some(cargo_bindings_path),
|
||||
)?;
|
||||
let selector = inspection
|
||||
.production_selector
|
||||
.ok_or("named cargo production selector is not available in the checked-in bindings")?;
|
||||
let report = RuntimeCargoSelectorInspectionOutput {
|
||||
cargo_types_dir: cargo_types_dir.display().to_string(),
|
||||
cargo_skin_pk4_path: cargo_skin_pk4_path.display().to_string(),
|
||||
selector,
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_runtime_inspect_cargo_price_selector(
|
||||
cargo_types_dir: &Path,
|
||||
cargo_skin_pk4_path: &Path,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let cargo_bindings_path =
|
||||
Path::new("artifacts/exports/rt3-1.06/event-effects-cargo-bindings.json");
|
||||
let inspection = inspect_cargo_economy_sources_with_bindings(
|
||||
cargo_types_dir,
|
||||
cargo_skin_pk4_path,
|
||||
Some(cargo_bindings_path),
|
||||
)?;
|
||||
let report = RuntimeCargoSelectorInspectionOutput {
|
||||
cargo_types_dir: cargo_types_dir.display().to_string(),
|
||||
cargo_skin_pk4_path: cargo_skin_pk4_path.display().to_string(),
|
||||
selector: inspection.price_selector,
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&report)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_runtime_inspect_win(win_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let report = RuntimeWinInspectionOutput {
|
||||
path: win_path.display().to_string(),
|
||||
|
|
@ -4665,9 +4752,14 @@ mod tests {
|
|||
);
|
||||
let stock_prices_shell_save_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../fixtures/runtime/packed-event-stock-prices-shell-save-slice-fixture.json");
|
||||
let game_won_shell_save_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../fixtures/runtime/packed-event-game-won-shell-save-slice-fixture.json");
|
||||
let merger_premium_shell_save_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||
"../../fixtures/runtime/packed-event-merger-premium-shell-save-slice-fixture.json",
|
||||
);
|
||||
let set_human_control_shell_save_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
|
||||
"../../fixtures/runtime/packed-event-set-human-control-shell-save-slice-fixture.json",
|
||||
);
|
||||
let investor_confidence_condition_save_fixture = PathBuf::from(env!(
|
||||
"CARGO_MANIFEST_DIR"
|
||||
))
|
||||
|
|
@ -4771,8 +4863,12 @@ mod tests {
|
|||
.expect("save-slice-backed credit-rating descriptor fixture should summarize");
|
||||
run_runtime_summarize_fixture(&stock_prices_shell_save_fixture)
|
||||
.expect("save-slice-backed shell-owned stock-prices fixture should summarize");
|
||||
run_runtime_summarize_fixture(&game_won_shell_save_fixture)
|
||||
.expect("save-slice-backed shell-owned game-won fixture should summarize");
|
||||
run_runtime_summarize_fixture(&merger_premium_shell_save_fixture)
|
||||
.expect("save-slice-backed shell-owned merger-premium fixture should summarize");
|
||||
run_runtime_summarize_fixture(&set_human_control_shell_save_fixture)
|
||||
.expect("save-slice-backed shell-owned set-human-control fixture should summarize");
|
||||
run_runtime_summarize_fixture(&investor_confidence_condition_save_fixture)
|
||||
.expect("save-slice-backed investor-confidence condition fixture should summarize");
|
||||
run_runtime_summarize_fixture(&management_attitude_condition_save_fixture)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ pub struct CargoEconomySourceReport {
|
|||
pub cargo_skin_only_visible_names: Vec<String>,
|
||||
pub live_registry_count: usize,
|
||||
pub live_registry_entries: Vec<CargoLiveRegistryEntry>,
|
||||
pub price_selector_candidate_excess_count: usize,
|
||||
pub price_selector_candidate_only_visible_names: Vec<String>,
|
||||
pub production_selector: Option<CargoSelectorReport>,
|
||||
pub price_selector: CargoSelectorReport,
|
||||
pub notes: Vec<String>,
|
||||
|
|
@ -271,7 +273,25 @@ fn build_cargo_economy_source_report(
|
|||
build_live_registry_entries(&cargo_types.entries, &cargo_skins.entries);
|
||||
let production_selector =
|
||||
cargo_bindings.map(|bindings| build_production_selector(bindings, &live_registry_entries));
|
||||
let price_selector_candidate_only_visible_names = production_selector
|
||||
.as_ref()
|
||||
.map(|selector| {
|
||||
let selector_names = selector
|
||||
.entries
|
||||
.iter()
|
||||
.map(|entry| entry.visible_name.as_str())
|
||||
.collect::<BTreeSet<_>>();
|
||||
live_registry_entries
|
||||
.iter()
|
||||
.filter(|entry| !selector_names.contains(entry.visible_name.as_str()))
|
||||
.map(|entry| entry.visible_name.clone())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let price_selector = build_price_selector(&live_registry_entries);
|
||||
let price_selector_candidate_excess_count = live_registry_entries
|
||||
.len()
|
||||
.saturating_sub(NAMED_CARGO_PRICE_DESCRIPTOR_ROW_COUNT);
|
||||
|
||||
let mut notes = Vec::new();
|
||||
notes.push(format!(
|
||||
|
|
@ -313,6 +333,8 @@ fn build_cargo_economy_source_report(
|
|||
cargo_skin_only_visible_names,
|
||||
live_registry_count: live_registry_entries.len(),
|
||||
live_registry_entries,
|
||||
price_selector_candidate_excess_count,
|
||||
price_selector_candidate_only_visible_names,
|
||||
production_selector,
|
||||
price_selector,
|
||||
notes,
|
||||
|
|
@ -661,6 +683,12 @@ mod tests {
|
|||
);
|
||||
assert!(!report.price_selector.exact_resolution);
|
||||
assert_eq!(report.price_selector.candidate_registry_count, 3);
|
||||
assert_eq!(report.price_selector_candidate_excess_count, 0);
|
||||
assert!(
|
||||
report
|
||||
.price_selector_candidate_only_visible_names
|
||||
.is_empty()
|
||||
);
|
||||
assert!(report.production_selector.is_none());
|
||||
}
|
||||
|
||||
|
|
@ -733,5 +761,11 @@ mod tests {
|
|||
]
|
||||
);
|
||||
assert_eq!(selector.entries[1].visible_name, "Coal");
|
||||
assert!(
|
||||
report
|
||||
.price_selector_candidate_only_visible_names
|
||||
.is_empty()
|
||||
);
|
||||
assert_eq!(report.price_selector_candidate_excess_count, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ const RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG: u32 = 0x000032c9;
|
|||
const RT3_SAVE_WORLD_BLOCK_LEN: usize = 0x4f2c;
|
||||
const RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET: usize = 0x1d;
|
||||
const RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET: usize = 0x21;
|
||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET: usize = 0x83;
|
||||
const RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET: usize = 0xc1;
|
||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET: usize = 0x0bbf;
|
||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT: usize = 16;
|
||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE: usize = 9;
|
||||
const EVENT_RUNTIME_COLLECTION_METADATA_TAG: u16 = 0x4e99;
|
||||
const EVENT_RUNTIME_COLLECTION_RECORDS_TAG: u16 = 0x4e9a;
|
||||
const EVENT_RUNTIME_COLLECTION_CLOSE_TAG: u16 = 0x4e9b;
|
||||
|
|
@ -1464,6 +1469,13 @@ pub struct SmpSaveWorldSelectionContextProbe {
|
|||
pub selected_chairman_profile_id_offset: usize,
|
||||
pub selected_chairman_profile_id: u32,
|
||||
pub selected_chairman_profile_id_hex: String,
|
||||
pub chairman_slot_selector_offset: usize,
|
||||
pub chairman_slot_selectors: Vec<u8>,
|
||||
pub campaign_override_flag_offset: usize,
|
||||
pub campaign_override_flag: u8,
|
||||
pub campaign_override_flag_hex: String,
|
||||
pub chairman_role_gate_offset: usize,
|
||||
pub chairman_role_gate_bytes: Vec<u8>,
|
||||
pub evidence: Vec<String>,
|
||||
}
|
||||
|
||||
|
|
@ -2551,6 +2563,13 @@ pub fn load_save_slice_from_report(
|
|||
"Raw save fixed world block exposes selected_chairman_profile_id={} at file offset 0x{:x}.",
|
||||
probe.selected_chairman_profile_id, probe.selected_chairman_profile_id_offset
|
||||
));
|
||||
notes.push(format!(
|
||||
"Raw save fixed world block also exposes {} chairman slot selector bytes at file offset 0x{:x} and campaign_override_flag={} at file offset 0x{:x}.",
|
||||
probe.chairman_slot_selectors.len(),
|
||||
probe.chairman_slot_selector_offset,
|
||||
probe.campaign_override_flag,
|
||||
probe.campaign_override_flag_offset
|
||||
));
|
||||
notes.push(
|
||||
"Raw save inspection still does not reconstruct full company_roster or chairman_profile_table payloads; the grounded package-save path only proves selection ids and header-level collection state for those families."
|
||||
.to_string(),
|
||||
|
|
@ -6933,8 +6952,31 @@ fn parse_save_world_selection_context_probe(
|
|||
payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET;
|
||||
let selected_chairman_profile_id_offset =
|
||||
payload_offset + RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET;
|
||||
let chairman_slot_selector_offset =
|
||||
payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET;
|
||||
let campaign_override_flag_offset =
|
||||
payload_offset + RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET;
|
||||
let chairman_role_gate_offset =
|
||||
payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET;
|
||||
let selected_company_id = read_u32_at(bytes, selected_company_id_offset)?;
|
||||
let selected_chairman_profile_id = read_u32_at(bytes, selected_chairman_profile_id_offset)?;
|
||||
let chairman_slot_selectors = bytes
|
||||
.get(
|
||||
chairman_slot_selector_offset
|
||||
..chairman_slot_selector_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT,
|
||||
)?
|
||||
.to_vec();
|
||||
let campaign_override_flag = *bytes.get(campaign_override_flag_offset)?;
|
||||
let chairman_role_gate_bytes = (0..RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT)
|
||||
.map(|slot_index| {
|
||||
bytes
|
||||
.get(
|
||||
chairman_role_gate_offset
|
||||
+ slot_index * RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE,
|
||||
)
|
||||
.copied()
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
return Some(SmpSaveWorldSelectionContextProbe {
|
||||
profile_family: profile.profile_family.clone(),
|
||||
source_kind: "save-direct-world-block".to_string(),
|
||||
|
|
@ -6949,6 +6991,13 @@ fn parse_save_world_selection_context_probe(
|
|||
selected_chairman_profile_id_offset,
|
||||
selected_chairman_profile_id,
|
||||
selected_chairman_profile_id_hex: format!("0x{selected_chairman_profile_id:08x}"),
|
||||
chairman_slot_selector_offset,
|
||||
chairman_slot_selectors,
|
||||
campaign_override_flag_offset,
|
||||
campaign_override_flag,
|
||||
campaign_override_flag_hex: format!("0x{campaign_override_flag:02x}"),
|
||||
chairman_role_gate_offset,
|
||||
chairman_role_gate_bytes,
|
||||
evidence: vec![
|
||||
format!(
|
||||
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
|
||||
|
|
@ -6964,6 +7013,19 @@ fn parse_save_world_selection_context_probe(
|
|||
"selected chairman profile id comes from payload +0x{:x} ([world+0x25])",
|
||||
RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET
|
||||
),
|
||||
format!(
|
||||
"16 chairman slot selector bytes come from payload +0x{:x} ([world+0x87])",
|
||||
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
|
||||
),
|
||||
format!(
|
||||
"campaign override flag comes from payload +0x{:x} ([world+0xc5])",
|
||||
RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET
|
||||
),
|
||||
format!(
|
||||
"chairman role-gate bytes come from payload +0x{:x} + slot*0x{:x} ([world+0x0bc3+slot*9])",
|
||||
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET,
|
||||
RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE
|
||||
),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
|
@ -13248,6 +13310,17 @@ mod tests {
|
|||
+ RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET
|
||||
+ 4]
|
||||
.copy_from_slice(&9u32.to_le_bytes());
|
||||
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
|
||||
..payload_offset
|
||||
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET
|
||||
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_COUNT]
|
||||
.copy_from_slice(&[3, 1, 4, 1, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
bytes[payload_offset + RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET] = 1;
|
||||
for (slot_index, role_gate) in [2u8, 1, 0, 2].into_iter().enumerate() {
|
||||
bytes[payload_offset
|
||||
+ RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET
|
||||
+ slot_index * RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_STRIDE] = role_gate;
|
||||
}
|
||||
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
|
||||
bytes[next_chunk_offset..next_chunk_offset + 4]
|
||||
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
|
||||
|
|
@ -13267,6 +13340,9 @@ mod tests {
|
|||
assert_eq!(probe.payload_offset, payload_offset);
|
||||
assert_eq!(probe.selected_company_id, 7);
|
||||
assert_eq!(probe.selected_chairman_profile_id, 9);
|
||||
assert_eq!(probe.chairman_slot_selectors[..6], [3, 1, 4, 1, 5, 9]);
|
||||
assert_eq!(probe.campaign_override_flag, 1);
|
||||
assert_eq!(probe.chairman_role_gate_bytes[..4], [2, 1, 0, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -13310,6 +13386,13 @@ mod tests {
|
|||
selected_chairman_profile_id_offset: 0x3f3,
|
||||
selected_chairman_profile_id: 9,
|
||||
selected_chairman_profile_id_hex: "0x00000009".to_string(),
|
||||
chairman_slot_selector_offset: 0x455,
|
||||
chairman_slot_selectors: vec![3, 1, 4, 1, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
campaign_override_flag_offset: 0x493,
|
||||
campaign_override_flag: 1,
|
||||
campaign_override_flag_hex: "0x01".to_string(),
|
||||
chairman_role_gate_offset: 0xf91,
|
||||
chairman_role_gate_bytes: vec![2, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
evidence: vec![],
|
||||
});
|
||||
|
||||
|
|
@ -13339,6 +13422,12 @@ mod tests {
|
|||
.iter()
|
||||
.any(|note| note.contains("selected_chairman_profile_id=9"))
|
||||
);
|
||||
assert!(
|
||||
slice
|
||||
.notes
|
||||
.iter()
|
||||
.any(|note| note.contains("campaign_override_flag=1"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ The highest-value next passes are now:
|
|||
but it now does reconstruct selection-only company/chairman context from the fixed save-side
|
||||
`0x32c8` world block, so overlay imports can reuse base rosters while honoring raw save-native
|
||||
selected company/chairman ids, and a tracked overlay fixture now pins that selection-only
|
||||
override path explicitly
|
||||
override path explicitly; the same fixed block now also exports the grounded campaign override
|
||||
byte plus the raw chairman slot selector and role-gate bytes as analysis-only save fields
|
||||
- a checked-in `EventEffects` export now exists at
|
||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer
|
||||
now exists at `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`
|
||||
|
|
@ -112,7 +113,8 @@ The highest-value next passes are now:
|
|||
`Prime Rate`
|
||||
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
||||
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
||||
descriptor residue, with tracked fixtures now pinning both finance rows explicitly
|
||||
descriptor residue, with tracked fixtures now pinning finance, scenario-outcome, and
|
||||
control-transfer shell rows explicitly
|
||||
- the recovered whole-game scalar economy/performance strip `59..104` now has a bounded runtime
|
||||
landing surface too: representative rows execute into `RuntimeState.world_scalar_overrides`
|
||||
through stable normalized keys such as `world.build_stations_cost` and
|
||||
|
|
@ -135,9 +137,10 @@ The highest-value next passes are now:
|
|||
`artifacts/exports/rt3-1.06/economy-cargo-sources.json` now parses both `CargoTypes` and the
|
||||
`Cargo106.PK4` `cargoSkin` descriptors through rehosted code, normalizes localized
|
||||
`~####Name` tokens into visible names, builds a merged live cargo registry, and derives an exact
|
||||
named cargo-production selector from the checked-in bindings; it also shows that the current
|
||||
1.06 visible-name union is `80`, so source recovery alone still does not prove the live
|
||||
price-selector ordering
|
||||
named cargo-production selector from the checked-in bindings; dedicated CLI inspector commands
|
||||
now expose that production selector and the unresolved price-selector candidate registry
|
||||
directly, and the same report still shows that the current 1.06 visible-name union is `80`, so
|
||||
source recovery alone still does not prove the live price-selector ordering
|
||||
- the add-building strip `503..519` is now explicitly classified as recovered shell-owned parity,
|
||||
with tracked fixture coverage, instead of generic unresolved descriptor residue
|
||||
- widen real packed-event executable coverage descriptor by descriptor after identity, target mask,
|
||||
|
|
|
|||
|
|
@ -61,8 +61,10 @@ Implemented today:
|
|||
without overlay snapshots when the checked-in documents include that context, while raw `.gms`
|
||||
inspection/export still leaves full company/chairman rosters absent; the grounded raw-save
|
||||
tranche now covers only selection-only company/chairman context from the fixed `0x32c8` world
|
||||
block, which overlay import can use to replace selected ids while preserving base rosters; a
|
||||
tracked overlay fixture now pins that selection-only override path explicitly
|
||||
block, which overlay import can use to replace selected ids while preserving base rosters; that
|
||||
same fixed block now also exports the grounded campaign override byte plus the raw chairman slot
|
||||
selector and role-gate bytes as analysis-only fields, and a tracked overlay fixture now pins the
|
||||
selection-only override path explicitly
|
||||
- a checked-in `EventEffects` export now exists too at
|
||||
`artifacts/exports/rt3-1.06/event-effects-table.json`, and a checked-in semantic closure layer
|
||||
now exists at `artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json`
|
||||
|
|
@ -74,7 +76,8 @@ Implemented today:
|
|||
`Prime Rate` now import through ordinary company target lowering
|
||||
- adjacent recovered finance/control-transfer descriptors such as `55` `Stock Prices` and `58`
|
||||
`Merger Premium` now land on explicit shell-owned descriptor parity instead of generic unmapped
|
||||
descriptor buckets, with tracked fixtures now pinning both finance rows explicitly
|
||||
descriptor buckets, with tracked fixtures now pinning finance, scenario-outcome, and
|
||||
control-transfer shell rows explicitly
|
||||
- the recovered whole-game scalar economy/performance strip `59..104` now has a bounded runtime
|
||||
landing surface too: representative descriptors import as `SetWorldScalarOverride` and land in
|
||||
`RuntimeState.world_scalar_overrides`
|
||||
|
|
@ -96,9 +99,10 @@ Implemented today:
|
|||
`artifacts/exports/rt3-1.06/economy-cargo-sources.json` now parses both `CargoTypes` and the
|
||||
`Cargo106.PK4` `cargoSkin` descriptors through rehosted code, normalizes localized
|
||||
`~####Name` tokens into visible names, builds a merged live cargo registry, and derives an exact
|
||||
named cargo-production selector from the checked-in bindings; it also shows that the current
|
||||
1.06 visible-name union is `80`, so source recovery alone still does not prove the live
|
||||
price-selector ordering
|
||||
named cargo-production selector from the checked-in bindings; dedicated CLI inspector commands
|
||||
now expose that production selector and the unresolved price-selector candidate registry
|
||||
directly, and the same report still shows that the current 1.06 visible-name union is `80`, so
|
||||
source recovery alone still does not prove the live price-selector ordering
|
||||
- the add-building strip `503..519` is now explicitly classified as recovered shell-owned parity
|
||||
with tracked fixture coverage, not generic unresolved descriptor residue
|
||||
- a minimal event-owned train surface and an opaque economic-status lane now exist in runtime
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"fixture_id": "packed-event-game-won-shell-save-slice-fixture",
|
||||
"source": {
|
||||
"kind": "captured-runtime",
|
||||
"description": "Fixture pinning the explicit shell-owned descriptor frontier for recovered Game Won rows."
|
||||
},
|
||||
"state_save_slice_path": "packed-event-game-won-shell-save-slice.json",
|
||||
"commands": [
|
||||
{
|
||||
"kind": "service_trigger_kind",
|
||||
"trigger_kind": 7
|
||||
}
|
||||
],
|
||||
"expected_summary": {
|
||||
"calendar_projection_source": "default-1830-placeholder",
|
||||
"calendar_projection_is_placeholder": true,
|
||||
"packed_event_collection_present": true,
|
||||
"packed_event_record_count": 1,
|
||||
"packed_event_decoded_record_count": 1,
|
||||
"packed_event_parity_only_record_count": 1,
|
||||
"packed_event_blocked_shell_owned_descriptor_count": 1,
|
||||
"event_runtime_record_count": 0,
|
||||
"total_event_record_service_count": 0,
|
||||
"total_trigger_dispatch_count": 1
|
||||
},
|
||||
"expected_state_fragment": {
|
||||
"packed_event_collection": {
|
||||
"records": [
|
||||
{
|
||||
"import_outcome": "blocked_shell_owned_descriptor"
|
||||
}
|
||||
]
|
||||
},
|
||||
"event_runtime_records": []
|
||||
}
|
||||
}
|
||||
110
fixtures/runtime/packed-event-game-won-shell-save-slice.json
Normal file
110
fixtures/runtime/packed-event-game-won-shell-save-slice.json
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"save_slice_id": "packed-event-game-won-shell-save-slice",
|
||||
"source": {
|
||||
"description": "Tracked save-slice document pinning a recovered shell-owned scenario outcome descriptor.",
|
||||
"original_save_filename": "captured-game-won-shell.gms",
|
||||
"original_save_sha256": "game-won-shell-sample-sha256",
|
||||
"notes": [
|
||||
"tracked as JSON save-slice document rather than raw .smp",
|
||||
"pins descriptor 4 as explicit shell-owned parity instead of generic descriptor residue"
|
||||
]
|
||||
},
|
||||
"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,
|
||||
"locomotive_catalog": null,
|
||||
"cargo_catalog": null,
|
||||
"company_roster": null,
|
||||
"chairman_profile_table": null,
|
||||
"special_conditions_table": null,
|
||||
"event_runtime_collection": {
|
||||
"source_kind": "packed-event-runtime-collection",
|
||||
"mechanism_family": "classic-save-rehydrate-v1",
|
||||
"mechanism_confidence": "grounded",
|
||||
"container_profile_family": "rt3-classic-save-container-v1",
|
||||
"metadata_tag_offset": 28800,
|
||||
"records_tag_offset": 29056,
|
||||
"close_tag_offset": 29568,
|
||||
"packed_state_version": 1001,
|
||||
"packed_state_version_hex": "0x000003e9",
|
||||
"live_id_bound": 75,
|
||||
"live_record_count": 1,
|
||||
"live_entry_ids": [75],
|
||||
"decoded_record_count": 1,
|
||||
"imported_runtime_record_count": 0,
|
||||
"records": [
|
||||
{
|
||||
"record_index": 0,
|
||||
"live_entry_id": 75,
|
||||
"payload_offset": 29058,
|
||||
"payload_len": 120,
|
||||
"decode_status": "parity_only",
|
||||
"payload_family": "real_packed_v1",
|
||||
"trigger_kind": 7,
|
||||
"active": null,
|
||||
"marks_collection_dirty": null,
|
||||
"one_shot": false,
|
||||
"compact_control": {
|
||||
"mode_byte_0x7ef": 6,
|
||||
"primary_selector_0x7f0": 99,
|
||||
"grouped_mode_0x7f4": 2,
|
||||
"one_shot_header_0x7f5": 1,
|
||||
"modifier_flag_0x7f9": 0,
|
||||
"modifier_flag_0x7fa": 0,
|
||||
"grouped_target_scope_ordinals_0x7fb": [0, 0, 0, 0],
|
||||
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||
"summary_toggle_0x800": 1,
|
||||
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
|
||||
},
|
||||
"text_bands": [],
|
||||
"standalone_condition_row_count": 0,
|
||||
"standalone_condition_rows": [],
|
||||
"negative_sentinel_scope": null,
|
||||
"grouped_effect_row_counts": [1, 0, 0, 0],
|
||||
"grouped_effect_rows": [
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 0,
|
||||
"descriptor_id": 4,
|
||||
"descriptor_label": "Game Won (Bronze)",
|
||||
"target_mask_bits": 2,
|
||||
"parameter_family": "scenario_outcome_shell_action",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 1,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "scalar_assignment",
|
||||
"semantic_family": "scalar_assignment",
|
||||
"semantic_preview": "Set Game Won (Bronze) to 1",
|
||||
"locomotive_name": null,
|
||||
"notes": [
|
||||
"descriptor recovered in the checked-in effect table as shell_owned parity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"decoded_conditions": [],
|
||||
"decoded_actions": [],
|
||||
"executable_import_ready": false,
|
||||
"notes": [
|
||||
"scenario-outcome descriptor is recovered but remains shell-owned parity"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": [
|
||||
"recovered shell-owned scenario outcome descriptor sample"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"fixture_id": "packed-event-set-human-control-shell-save-slice-fixture",
|
||||
"source": {
|
||||
"kind": "captured-runtime",
|
||||
"description": "Fixture pinning the explicit shell-owned descriptor frontier for recovered Set to human control rows."
|
||||
},
|
||||
"state_save_slice_path": "packed-event-set-human-control-shell-save-slice.json",
|
||||
"commands": [
|
||||
{
|
||||
"kind": "service_trigger_kind",
|
||||
"trigger_kind": 7
|
||||
}
|
||||
],
|
||||
"expected_summary": {
|
||||
"calendar_projection_source": "default-1830-placeholder",
|
||||
"calendar_projection_is_placeholder": true,
|
||||
"company_count": 1,
|
||||
"chairman_profile_count": 1,
|
||||
"selected_company_id": 1,
|
||||
"selected_chairman_profile_id": 1,
|
||||
"packed_event_collection_present": true,
|
||||
"packed_event_record_count": 1,
|
||||
"packed_event_decoded_record_count": 1,
|
||||
"packed_event_parity_only_record_count": 1,
|
||||
"packed_event_blocked_shell_owned_descriptor_count": 1,
|
||||
"event_runtime_record_count": 0,
|
||||
"total_event_record_service_count": 0,
|
||||
"total_trigger_dispatch_count": 1
|
||||
},
|
||||
"expected_state_fragment": {
|
||||
"packed_event_collection": {
|
||||
"records": [
|
||||
{
|
||||
"import_outcome": "blocked_shell_owned_descriptor"
|
||||
}
|
||||
]
|
||||
},
|
||||
"event_runtime_records": []
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
"format_version": 1,
|
||||
"save_slice_id": "packed-event-set-human-control-shell-save-slice",
|
||||
"source": {
|
||||
"description": "Tracked save-slice document pinning a recovered shell-owned control-transfer descriptor.",
|
||||
"original_save_filename": "captured-set-human-control-shell.gms",
|
||||
"original_save_sha256": "set-human-control-shell-sample-sha256",
|
||||
"notes": [
|
||||
"tracked as JSON save-slice document rather than raw .smp",
|
||||
"pins descriptor 24 as explicit shell-owned parity instead of generic descriptor residue"
|
||||
]
|
||||
},
|
||||
"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,
|
||||
"locomotive_catalog": null,
|
||||
"cargo_catalog": null,
|
||||
"special_conditions_table": null,
|
||||
"event_runtime_collection": {
|
||||
"source_kind": "packed-event-runtime-collection",
|
||||
"mechanism_family": "classic-save-rehydrate-v1",
|
||||
"mechanism_confidence": "grounded",
|
||||
"container_profile_family": "rt3-classic-save-container-v1",
|
||||
"metadata_tag_offset": 28896,
|
||||
"records_tag_offset": 29152,
|
||||
"close_tag_offset": 29664,
|
||||
"packed_state_version": 1001,
|
||||
"packed_state_version_hex": "0x000003e9",
|
||||
"live_id_bound": 75,
|
||||
"live_record_count": 1,
|
||||
"live_entry_ids": [75],
|
||||
"decoded_record_count": 1,
|
||||
"imported_runtime_record_count": 0,
|
||||
"records": [
|
||||
{
|
||||
"record_index": 0,
|
||||
"live_entry_id": 75,
|
||||
"payload_offset": 29154,
|
||||
"payload_len": 120,
|
||||
"decode_status": "parity_only",
|
||||
"payload_family": "real_packed_v1",
|
||||
"trigger_kind": 7,
|
||||
"active": null,
|
||||
"marks_collection_dirty": null,
|
||||
"one_shot": false,
|
||||
"compact_control": {
|
||||
"mode_byte_0x7ef": 6,
|
||||
"primary_selector_0x7f0": 99,
|
||||
"grouped_mode_0x7f4": 2,
|
||||
"one_shot_header_0x7f5": 1,
|
||||
"modifier_flag_0x7f9": 1,
|
||||
"modifier_flag_0x7fa": 0,
|
||||
"grouped_target_scope_ordinals_0x7fb": [0, 1, 2, 3],
|
||||
"grouped_scope_checkboxes_0x7ff": [1, 0, 0, 0],
|
||||
"summary_toggle_0x800": 1,
|
||||
"grouped_territory_selectors_0x80f": [-1, -1, -1, -1]
|
||||
},
|
||||
"text_bands": [],
|
||||
"standalone_condition_row_count": 0,
|
||||
"standalone_condition_rows": [],
|
||||
"negative_sentinel_scope": null,
|
||||
"grouped_effect_row_counts": [1, 0, 0, 0],
|
||||
"grouped_effect_rows": [
|
||||
{
|
||||
"group_index": 0,
|
||||
"row_index": 0,
|
||||
"descriptor_id": 24,
|
||||
"descriptor_label": "Set to human control",
|
||||
"target_mask_bits": 2,
|
||||
"parameter_family": "control_transfer_shell_action",
|
||||
"opcode": 3,
|
||||
"raw_scalar_value": 1,
|
||||
"value_byte_0x09": 0,
|
||||
"value_dword_0x0d": 0,
|
||||
"value_byte_0x11": 0,
|
||||
"value_byte_0x12": 0,
|
||||
"value_word_0x14": 0,
|
||||
"value_word_0x16": 0,
|
||||
"row_shape": "scalar_assignment",
|
||||
"semantic_family": "scalar_assignment",
|
||||
"semantic_preview": "Set Set to human control to 1",
|
||||
"locomotive_name": null,
|
||||
"notes": [
|
||||
"descriptor recovered in the checked-in effect table as shell_owned parity"
|
||||
]
|
||||
}
|
||||
],
|
||||
"decoded_conditions": [],
|
||||
"decoded_actions": [],
|
||||
"executable_import_ready": false,
|
||||
"notes": [
|
||||
"control-transfer descriptor is recovered but remains shell-owned parity"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": [
|
||||
"recovered shell-owned control-transfer descriptor sample"
|
||||
],
|
||||
"company_roster": {
|
||||
"source_kind": "tracked-save-slice-company-roster",
|
||||
"semantic_family": "save-slice-runtime-company-context",
|
||||
"observed_entry_count": 1,
|
||||
"selected_company_id": 1,
|
||||
"entries": [
|
||||
{
|
||||
"company_id": 1,
|
||||
"active": true,
|
||||
"controller_kind": "human",
|
||||
"current_cash": 200,
|
||||
"debt": 0,
|
||||
"credit_rating_score": 700,
|
||||
"prime_rate": 5,
|
||||
"available_track_laying_capacity": 6,
|
||||
"track_piece_counts": {
|
||||
"total": 12,
|
||||
"single": 4,
|
||||
"double": 4,
|
||||
"transition": 0,
|
||||
"electric": 2,
|
||||
"non_electric": 10
|
||||
},
|
||||
"linked_chairman_profile_id": 1,
|
||||
"book_value_per_share": 1800,
|
||||
"investor_confidence": 40,
|
||||
"management_attitude": 45,
|
||||
"takeover_cooldown_year": null,
|
||||
"merger_cooldown_year": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"chairman_profile_table": {
|
||||
"source_kind": "tracked-save-slice-chairman-profile-table",
|
||||
"semantic_family": "save-slice-runtime-chairman-context",
|
||||
"observed_entry_count": 1,
|
||||
"selected_chairman_profile_id": 1,
|
||||
"entries": [
|
||||
{
|
||||
"profile_id": 1,
|
||||
"name": "Chairman One",
|
||||
"active": true,
|
||||
"current_cash": 500,
|
||||
"linked_company_id": 1,
|
||||
"company_holdings": {
|
||||
"1": 1000
|
||||
},
|
||||
"holdings_value_total": 700,
|
||||
"net_worth_total": 1200,
|
||||
"purchasing_power_total": 1500
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue