Recover locomotive policy packed event descriptors
This commit is contained in:
parent
1e36e6c929
commit
c04c19ac82
9 changed files with 679 additions and 18 deletions
14
README.md
14
README.md
|
|
@ -47,11 +47,15 @@ is broader now too: checked-in world-flag condition ids can lower into `world_fl
|
||||||
for boolean equality/inequality forms, so real packed records can gate whole-game effects on
|
for boolean equality/inequality forms, so real packed records can gate whole-game effects on
|
||||||
existing `world_flags` without fixture-authored placeholder ids. The tracked parity save-slice no
|
existing `world_flags` without fixture-authored placeholder ids. The tracked parity save-slice no
|
||||||
longer depends on a raw `unsupported_framing` placeholder either: its remaining residue is now one
|
longer depends on a raw `unsupported_framing` placeholder either: its remaining residue is now one
|
||||||
structured `real_packed_v1` record that lands in the explicit `blocked_unmapped_real_descriptor`
|
recovered locomotives-page `real_packed_v1` record that lands in the explicit
|
||||||
bucket. Explicit unmapped world-condition and world-descriptor frontier buckets still remain where
|
`blocked_unmapped_world_descriptor` bucket. The next recovered descriptor band is now partially
|
||||||
current checked-in metadata stops. Shell purchase-flow and selected-profile parity remain out of
|
executable too: descriptors `454..456` (`All Steam/Diesel/Electric Locos Avail.`) now lower
|
||||||
scope. Mixed supported/unsupported real rows still stay parity-only. The PE32 hook remains useful
|
through checked-in metadata into keyed `world_flags`, while the wider locomotive availability/cost
|
||||||
as capture and integration tooling, but it is no longer the main execution milestone.
|
scalar bands remain recovered-but-parity-only until per-locomotive identity is grounded. Explicit
|
||||||
|
unmapped world-condition and world-descriptor frontier buckets still remain where current
|
||||||
|
checked-in metadata stops. Shell purchase-flow 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.
|
||||||
|
|
||||||
## Project Docs
|
## Project Docs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4485,6 +4485,102 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn leaves_recovered_locomotive_availability_rows_blocked_unmapped_world_descriptor() {
|
||||||
|
let save_slice = SmpLoadedSaveSlice {
|
||||||
|
file_extension_hint: Some("gms".to_string()),
|
||||||
|
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||||
|
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||||
|
mechanism_confidence: "grounded".to_string(),
|
||||||
|
trailer_family: None,
|
||||||
|
bridge_family: None,
|
||||||
|
profile: None,
|
||||||
|
candidate_availability_table: None,
|
||||||
|
special_conditions_table: None,
|
||||||
|
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
|
||||||
|
source_kind: "packed-event-runtime-collection".to_string(),
|
||||||
|
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||||
|
mechanism_confidence: "grounded".to_string(),
|
||||||
|
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||||
|
metadata_tag_offset: 0x7100,
|
||||||
|
records_tag_offset: 0x7200,
|
||||||
|
close_tag_offset: 0x7600,
|
||||||
|
packed_state_version: 0x3e9,
|
||||||
|
packed_state_version_hex: "0x000003e9".to_string(),
|
||||||
|
live_id_bound: 31,
|
||||||
|
live_record_count: 1,
|
||||||
|
live_entry_ids: vec![31],
|
||||||
|
decoded_record_count: 1,
|
||||||
|
imported_runtime_record_count: 0,
|
||||||
|
records: vec![crate::SmpLoadedPackedEventRecordSummary {
|
||||||
|
record_index: 0,
|
||||||
|
live_entry_id: 31,
|
||||||
|
payload_offset: Some(0x7202),
|
||||||
|
payload_len: Some(96),
|
||||||
|
decode_status: "parity_only".to_string(),
|
||||||
|
payload_family: "real_packed_v1".to_string(),
|
||||||
|
trigger_kind: Some(6),
|
||||||
|
active: None,
|
||||||
|
marks_collection_dirty: None,
|
||||||
|
one_shot: Some(false),
|
||||||
|
compact_control: Some(real_compact_control()),
|
||||||
|
text_bands: vec![],
|
||||||
|
standalone_condition_row_count: 0,
|
||||||
|
standalone_condition_rows: vec![],
|
||||||
|
negative_sentinel_scope: None,
|
||||||
|
grouped_effect_row_counts: vec![1, 0, 0, 0],
|
||||||
|
grouped_effect_rows: vec![crate::SmpLoadedPackedEventGroupedEffectRowSummary {
|
||||||
|
group_index: 0,
|
||||||
|
row_index: 0,
|
||||||
|
descriptor_id: 250,
|
||||||
|
descriptor_label: Some("Unknown Loco Available".to_string()),
|
||||||
|
target_mask_bits: Some(0x08),
|
||||||
|
parameter_family: Some("locomotive_availability_scalar".to_string()),
|
||||||
|
opcode: 3,
|
||||||
|
raw_scalar_value: 42,
|
||||||
|
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".to_string(),
|
||||||
|
semantic_family: Some("scalar_assignment".to_string()),
|
||||||
|
semantic_preview: Some("Set Unknown Loco Available to 42".to_string()),
|
||||||
|
locomotive_name: None,
|
||||||
|
notes: vec![],
|
||||||
|
}],
|
||||||
|
decoded_conditions: Vec::new(),
|
||||||
|
decoded_actions: vec![],
|
||||||
|
executable_import_ready: false,
|
||||||
|
notes: vec![
|
||||||
|
"decoded from grounded real 0x4e9a row framing".to_string(),
|
||||||
|
"recovered locomotive availability descriptor family remains parity-only"
|
||||||
|
.to_string(),
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
notes: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let import = project_save_slice_to_runtime_state_import(
|
||||||
|
&save_slice,
|
||||||
|
"packed-events-recovered-locomotive-availability-frontier",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("save slice should project");
|
||||||
|
|
||||||
|
assert!(import.state.event_runtime_records.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
import
|
||||||
|
.state
|
||||||
|
.packed_event_collection
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
|
||||||
|
Some("blocked_unmapped_world_descriptor")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlays_real_company_cash_descriptor_into_executable_runtime_record() {
|
fn overlays_real_company_cash_descriptor_into_executable_runtime_record() {
|
||||||
let base_state = RuntimeState {
|
let base_state = RuntimeState {
|
||||||
|
|
@ -5919,6 +6015,117 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overlays_recovered_locomotive_policy_descriptors_into_executable_runtime_record() {
|
||||||
|
let base_state = state();
|
||||||
|
let save_slice = SmpLoadedSaveSlice {
|
||||||
|
file_extension_hint: Some("gms".to_string()),
|
||||||
|
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||||
|
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||||
|
mechanism_confidence: "grounded".to_string(),
|
||||||
|
trailer_family: None,
|
||||||
|
bridge_family: None,
|
||||||
|
profile: None,
|
||||||
|
candidate_availability_table: None,
|
||||||
|
special_conditions_table: None,
|
||||||
|
event_runtime_collection: Some(crate::SmpLoadedEventRuntimeCollectionSummary {
|
||||||
|
source_kind: "packed-event-runtime-collection".to_string(),
|
||||||
|
mechanism_family: "classic-save-rehydrate-v1".to_string(),
|
||||||
|
mechanism_confidence: "grounded".to_string(),
|
||||||
|
container_profile_family: Some("rt3-classic-save-container-v1".to_string()),
|
||||||
|
metadata_tag_offset: 0x7100,
|
||||||
|
records_tag_offset: 0x7200,
|
||||||
|
close_tag_offset: 0x7600,
|
||||||
|
packed_state_version: 0x3e9,
|
||||||
|
packed_state_version_hex: "0x000003e9".to_string(),
|
||||||
|
live_id_bound: 29,
|
||||||
|
live_record_count: 1,
|
||||||
|
live_entry_ids: vec![29],
|
||||||
|
decoded_record_count: 1,
|
||||||
|
imported_runtime_record_count: 1,
|
||||||
|
records: vec![crate::SmpLoadedPackedEventRecordSummary {
|
||||||
|
record_index: 0,
|
||||||
|
live_entry_id: 29,
|
||||||
|
payload_offset: Some(0x7200),
|
||||||
|
payload_len: Some(160),
|
||||||
|
decode_status: "executable".to_string(),
|
||||||
|
payload_family: "real_packed_v1".to_string(),
|
||||||
|
trigger_kind: Some(7),
|
||||||
|
active: None,
|
||||||
|
marks_collection_dirty: None,
|
||||||
|
one_shot: Some(false),
|
||||||
|
compact_control: Some(real_compact_control()),
|
||||||
|
text_bands: packed_text_bands(),
|
||||||
|
standalone_condition_row_count: 0,
|
||||||
|
standalone_condition_rows: vec![],
|
||||||
|
negative_sentinel_scope: None,
|
||||||
|
grouped_effect_row_counts: vec![3, 0, 0, 0],
|
||||||
|
grouped_effect_rows: vec![
|
||||||
|
real_world_flag_row(454, "All Steam Locos Avail.", true),
|
||||||
|
real_world_flag_row(455, "All Diesel Locos Avail.", false),
|
||||||
|
real_world_flag_row(456, "All Electric Locos Avail.", true),
|
||||||
|
],
|
||||||
|
decoded_conditions: Vec::new(),
|
||||||
|
decoded_actions: vec![
|
||||||
|
RuntimeEffect::SetWorldFlag {
|
||||||
|
key: "world.all_steam_locos_available".to_string(),
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
RuntimeEffect::SetWorldFlag {
|
||||||
|
key: "world.all_diesel_locos_available".to_string(),
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
RuntimeEffect::SetWorldFlag {
|
||||||
|
key: "world.all_electric_locos_available".to_string(),
|
||||||
|
value: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
executable_import_ready: true,
|
||||||
|
notes: vec![
|
||||||
|
"recovered locomotive policy descriptor band now imports as keyed world flags"
|
||||||
|
.to_string(),
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
notes: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut import = project_save_slice_overlay_to_runtime_state_import(
|
||||||
|
&base_state,
|
||||||
|
&save_slice,
|
||||||
|
"real-locomotive-policy-overlay",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("overlay import should project");
|
||||||
|
|
||||||
|
crate::execute_step_command(
|
||||||
|
&mut import.state,
|
||||||
|
&crate::StepCommand::ServiceTriggerKind { trigger_kind: 7 },
|
||||||
|
)
|
||||||
|
.expect("trigger service should execute");
|
||||||
|
assert_eq!(
|
||||||
|
import
|
||||||
|
.state
|
||||||
|
.world_flags
|
||||||
|
.get("world.all_steam_locos_available"),
|
||||||
|
Some(&true)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
import
|
||||||
|
.state
|
||||||
|
.world_flags
|
||||||
|
.get("world.all_diesel_locos_available"),
|
||||||
|
Some(&false)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
import
|
||||||
|
.state
|
||||||
|
.world_flags
|
||||||
|
.get("world.all_electric_locos_available"),
|
||||||
|
Some(&true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn overlays_real_world_flag_condition_into_executable_runtime_record() {
|
fn overlays_real_world_flag_condition_into_executable_runtime_record() {
|
||||||
let mut base_state = state();
|
let mut base_state = state();
|
||||||
|
|
|
||||||
|
|
@ -2785,10 +2785,129 @@ fn real_grouped_effect_descriptor_metadata(
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.find(|metadata| metadata.descriptor_id == descriptor_id)
|
.find(|metadata| metadata.descriptor_id == descriptor_id)
|
||||||
|
.or_else(|| recovered_cargo_production_descriptor_metadata(descriptor_id))
|
||||||
|
.or_else(|| recovered_locomotive_availability_descriptor_metadata(descriptor_id))
|
||||||
|
.or_else(|| recovered_locomotive_cost_descriptor_metadata(descriptor_id))
|
||||||
|
.or_else(|| recovered_territory_access_cost_descriptor_metadata(descriptor_id))
|
||||||
|
.or_else(|| recovered_locomotive_policy_descriptor_metadata(descriptor_id))
|
||||||
.or_else(|| special_condition_world_scalar_descriptor_metadata(descriptor_id))
|
.or_else(|| special_condition_world_scalar_descriptor_metadata(descriptor_id))
|
||||||
.or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id))
|
.or_else(|| special_condition_world_toggle_descriptor_metadata(descriptor_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recovered_cargo_production_descriptor_metadata(
|
||||||
|
descriptor_id: u32,
|
||||||
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
(230..=240)
|
||||||
|
.contains(&descriptor_id)
|
||||||
|
.then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Unknown Cargo Production",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "unknown_cargo_production_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recovered_locomotive_availability_descriptor_metadata(
|
||||||
|
descriptor_id: u32,
|
||||||
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
(241..=351)
|
||||||
|
.contains(&descriptor_id)
|
||||||
|
.then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Unknown Loco Available",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "locomotive_availability_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
(457..=474)
|
||||||
|
.contains(&descriptor_id)
|
||||||
|
.then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Unknown Loco Available",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "locomotive_availability_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recovered_locomotive_cost_descriptor_metadata(
|
||||||
|
descriptor_id: u32,
|
||||||
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
(352..=451)
|
||||||
|
.contains(&descriptor_id)
|
||||||
|
.then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Unknown Loco Cost",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "locomotive_cost_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
(475..=500)
|
||||||
|
.contains(&descriptor_id)
|
||||||
|
.then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Unknown Loco Cost",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "locomotive_cost_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recovered_territory_access_cost_descriptor_metadata(
|
||||||
|
descriptor_id: u32,
|
||||||
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
(descriptor_id == 453).then_some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "Territory access cost",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "territory_access_cost_scalar",
|
||||||
|
runtime_key: None,
|
||||||
|
executable_in_runtime: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recovered_locomotive_policy_descriptor_metadata(
|
||||||
|
descriptor_id: u32,
|
||||||
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
match descriptor_id {
|
||||||
|
454 => Some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "All Steam Locos Avail.",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "world_flag_toggle",
|
||||||
|
runtime_key: Some("world.all_steam_locos_available"),
|
||||||
|
executable_in_runtime: true,
|
||||||
|
}),
|
||||||
|
455 => Some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "All Diesel Locos Avail.",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "world_flag_toggle",
|
||||||
|
runtime_key: Some("world.all_diesel_locos_available"),
|
||||||
|
executable_in_runtime: true,
|
||||||
|
}),
|
||||||
|
456 => Some(RealGroupedEffectDescriptorMetadata {
|
||||||
|
descriptor_id,
|
||||||
|
label: "All Electric Locos Avail.",
|
||||||
|
target_mask_bits: 0x08,
|
||||||
|
parameter_family: "world_flag_toggle",
|
||||||
|
runtime_key: Some("world.all_electric_locos_available"),
|
||||||
|
executable_in_runtime: true,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn special_condition_world_scalar_descriptor_metadata(
|
fn special_condition_world_scalar_descriptor_metadata(
|
||||||
descriptor_id: u32,
|
descriptor_id: u32,
|
||||||
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
) -> Option<RealGroupedEffectDescriptorMetadata> {
|
||||||
|
|
@ -9087,6 +9206,106 @@ mod tests {
|
||||||
assert!(metadata.executable_in_runtime);
|
assert!(metadata.executable_in_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn looks_up_recovered_locomotive_availability_descriptor_metadata() {
|
||||||
|
let metadata =
|
||||||
|
real_grouped_effect_descriptor_metadata(250).expect("descriptor metadata should exist");
|
||||||
|
|
||||||
|
assert_eq!(metadata.label, "Unknown Loco Available");
|
||||||
|
assert_eq!(metadata.target_mask_bits, 0x08);
|
||||||
|
assert_eq!(metadata.parameter_family, "locomotive_availability_scalar");
|
||||||
|
assert_eq!(metadata.runtime_key, None);
|
||||||
|
assert!(!metadata.executable_in_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn looks_up_recovered_locomotive_policy_descriptor_metadata() {
|
||||||
|
let metadata =
|
||||||
|
real_grouped_effect_descriptor_metadata(454).expect("descriptor metadata should exist");
|
||||||
|
|
||||||
|
assert_eq!(metadata.label, "All Steam Locos Avail.");
|
||||||
|
assert_eq!(metadata.parameter_family, "world_flag_toggle");
|
||||||
|
assert_eq!(
|
||||||
|
metadata.runtime_key,
|
||||||
|
Some("world.all_steam_locos_available")
|
||||||
|
);
|
||||||
|
assert!(metadata.executable_in_runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decodes_recovered_locomotive_policy_descriptor_from_checked_in_metadata() {
|
||||||
|
let grouped_row = build_real_grouped_effect_row(RealGroupedEffectRowSpec {
|
||||||
|
descriptor_id: 454,
|
||||||
|
opcode: 0,
|
||||||
|
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,
|
||||||
|
locomotive_name: None,
|
||||||
|
});
|
||||||
|
let group0_rows = vec![grouped_row];
|
||||||
|
let record_body = build_real_event_record(
|
||||||
|
[b"Locos", b"", b"", b"", b"", b""],
|
||||||
|
Some(RealCompactControlSpec {
|
||||||
|
mode_byte_0x7ef: 6,
|
||||||
|
primary_selector_0x7f0: 0,
|
||||||
|
grouped_mode_0x7f4: 2,
|
||||||
|
one_shot_header_0x7f5: 0,
|
||||||
|
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],
|
||||||
|
}),
|
||||||
|
&[],
|
||||||
|
[&group0_rows, &[], &[], &[]],
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_METADATA_TAG.to_le_bytes());
|
||||||
|
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_PACKED_STATE_VERSION.to_le_bytes());
|
||||||
|
let header_words = [1u32, 4, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
for word in header_words {
|
||||||
|
bytes.extend_from_slice(&word.to_le_bytes());
|
||||||
|
}
|
||||||
|
bytes.extend_from_slice(&[0x00, 0x00]);
|
||||||
|
bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd]);
|
||||||
|
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_RECORDS_TAG.to_le_bytes());
|
||||||
|
bytes.extend_from_slice(&record_body);
|
||||||
|
bytes.extend_from_slice(&EVENT_RUNTIME_COLLECTION_CLOSE_TAG.to_le_bytes());
|
||||||
|
|
||||||
|
let report = inspect_smp_bytes(&bytes);
|
||||||
|
let summary = report
|
||||||
|
.event_runtime_collection_summary
|
||||||
|
.as_ref()
|
||||||
|
.expect("event runtime collection summary should parse");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
summary.records[0].grouped_effect_rows[0]
|
||||||
|
.descriptor_label
|
||||||
|
.as_deref(),
|
||||||
|
Some("All Steam Locos Avail.")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.records[0].grouped_effect_rows[0]
|
||||||
|
.parameter_family
|
||||||
|
.as_deref(),
|
||||||
|
Some("world_flag_toggle")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
summary.records[0].decoded_actions,
|
||||||
|
vec![RuntimeEffect::SetWorldFlag {
|
||||||
|
key: "world.all_steam_locos_available".to_string(),
|
||||||
|
value: true,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
assert!(summary.records[0].executable_import_ready);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn looks_up_checked_in_deactivate_player_descriptor_metadata() {
|
fn looks_up_checked_in_deactivate_player_descriptor_metadata() {
|
||||||
let metadata =
|
let metadata =
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,13 @@ The highest-value next passes are now:
|
||||||
can lower into `world_flag_equals` gates for boolean equality/inequality forms, so real packed
|
can lower into `world_flag_equals` gates for boolean equality/inequality forms, so real packed
|
||||||
rows can gate whole-game effects on existing `world_flags`
|
rows can gate whole-game effects on existing `world_flags`
|
||||||
- the tracked parity save-slice now keeps its remaining non-imported residue as structured
|
- the tracked parity save-slice now keeps its remaining non-imported residue as structured
|
||||||
`real_packed_v1` parity records, with the first captured leftover moved out of
|
`real_packed_v1` parity records, with the first captured leftover now identified as the
|
||||||
`unsupported_framing` and into the explicit `blocked_unmapped_real_descriptor` frontier
|
locomotives-page `Unknown Loco Available` band and moved onto the explicit
|
||||||
|
`blocked_unmapped_world_descriptor` frontier
|
||||||
|
- the next recovered locomotives-page descriptor batch is partially executable too:
|
||||||
|
descriptors `454..456` (`All Steam/Diesel/Electric Locos Avail.`) now lower through checked-in
|
||||||
|
metadata into keyed `world_flags`, while the wider locomotive availability/cost scalar bands
|
||||||
|
remain recovered-but-parity-only until per-locomotive identity is grounded
|
||||||
- keep in mind that the current local `.gms` corpus still exports with no packed event collection,
|
- 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
|
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
|
- use `rrt-hook` primarily as optional capture or integration tooling, not as the first execution
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,12 @@ Implemented today:
|
||||||
`world_flags` through `world_flag_equals` without fixture-authored placeholder ids
|
`world_flags` through `world_flag_equals` without fixture-authored placeholder ids
|
||||||
- the tracked parity save-slice no longer preserves an opaque `unsupported_framing` record; its
|
- the tracked parity save-slice no longer preserves an opaque `unsupported_framing` record; its
|
||||||
remaining captured residue is now structurally decoded `real_packed_v1` parity state that lands
|
remaining captured residue is now structurally decoded `real_packed_v1` parity state that lands
|
||||||
in existing explicit blocker buckets
|
in existing explicit blocker buckets, with the first leftover now identified as the
|
||||||
|
locomotives-page `Unknown Loco Available` band instead of anonymous descriptor residue
|
||||||
|
- the next recovered locomotives-page descriptor band is now partially executable too:
|
||||||
|
descriptors `230..240`, `241..351`, `352..451`, `453`, and `457..500` now carry recovered
|
||||||
|
world-side scalar metadata, while descriptors `454..456` (`All Steam/Diesel/Electric Locos
|
||||||
|
Avail.`) now execute as keyed `world_flags`
|
||||||
|
|
||||||
That means the next implementation work is breadth, not bootstrap. The recommended next slice is
|
That means the next implementation work is breadth, not bootstrap. The recommended next slice is
|
||||||
broader real grouped-descriptor and ordinary condition-id coverage beyond the current access,
|
broader real grouped-descriptor and ordinary condition-id coverage beyond the current access,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@
|
||||||
"packed_event_blocked_missing_condition_context_count": 0,
|
"packed_event_blocked_missing_condition_context_count": 0,
|
||||||
"packed_event_blocked_territory_condition_scope_count": 0,
|
"packed_event_blocked_territory_condition_scope_count": 0,
|
||||||
"packed_event_blocked_missing_compact_control_count": 0,
|
"packed_event_blocked_missing_compact_control_count": 0,
|
||||||
"packed_event_blocked_unmapped_real_descriptor_count": 1,
|
"packed_event_blocked_unmapped_real_descriptor_count": 0,
|
||||||
|
"packed_event_blocked_unmapped_world_descriptor_count": 1,
|
||||||
"packed_event_blocked_structural_only_count": 0,
|
"packed_event_blocked_structural_only_count": 0,
|
||||||
"event_runtime_record_count": 1,
|
"event_runtime_record_count": 1,
|
||||||
"total_company_cash": 0
|
"total_company_cash": 0
|
||||||
|
|
@ -47,10 +48,15 @@
|
||||||
{
|
{
|
||||||
"decode_status": "parity_only",
|
"decode_status": "parity_only",
|
||||||
"payload_family": "real_packed_v1",
|
"payload_family": "real_packed_v1",
|
||||||
"import_outcome": "blocked_unmapped_real_descriptor",
|
"import_outcome": "blocked_unmapped_world_descriptor",
|
||||||
"grouped_effect_rows": [
|
"grouped_effect_rows": [
|
||||||
{
|
{
|
||||||
"descriptor_id": 250,
|
"descriptor_id": 250,
|
||||||
|
"descriptor_label": "Unknown Loco Available",
|
||||||
|
"target_mask_bits": 8,
|
||||||
|
"parameter_family": "locomotive_availability_scalar",
|
||||||
|
"semantic_family": "scalar_assignment",
|
||||||
|
"semantic_preview": "Set Unknown Loco Available to 42",
|
||||||
"row_shape": "scalar_assignment"
|
"row_shape": "scalar_assignment"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"original_save_sha256": "parity-sample-sha256",
|
"original_save_sha256": "parity-sample-sha256",
|
||||||
"notes": [
|
"notes": [
|
||||||
"tracked as JSON save-slice document rather than raw .smp",
|
"tracked as JSON save-slice document rather than raw .smp",
|
||||||
"preserves one structured-but-unmapped row and one semantically decoded-but-parity-only row"
|
"preserves one recovered-but-unmapped locomotive policy row and one semantically decoded-but-parity-only row"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"save_slice": {
|
"save_slice": {
|
||||||
|
|
@ -66,9 +66,9 @@
|
||||||
"group_index": 0,
|
"group_index": 0,
|
||||||
"row_index": 0,
|
"row_index": 0,
|
||||||
"descriptor_id": 250,
|
"descriptor_id": 250,
|
||||||
"descriptor_label": null,
|
"descriptor_label": "Unknown Loco Available",
|
||||||
"target_mask_bits": null,
|
"target_mask_bits": 8,
|
||||||
"parameter_family": null,
|
"parameter_family": "locomotive_availability_scalar",
|
||||||
"opcode": 3,
|
"opcode": 3,
|
||||||
"raw_scalar_value": 42,
|
"raw_scalar_value": 42,
|
||||||
"value_byte_0x09": 0,
|
"value_byte_0x09": 0,
|
||||||
|
|
@ -78,11 +78,11 @@
|
||||||
"value_word_0x14": 0,
|
"value_word_0x14": 0,
|
||||||
"value_word_0x16": 0,
|
"value_word_0x16": 0,
|
||||||
"row_shape": "scalar_assignment",
|
"row_shape": "scalar_assignment",
|
||||||
"semantic_family": null,
|
"semantic_family": "scalar_assignment",
|
||||||
"semantic_preview": null,
|
"semantic_preview": "Set Unknown Loco Available to 42",
|
||||||
"locomotive_name": null,
|
"locomotive_name": null,
|
||||||
"notes": [
|
"notes": [
|
||||||
"real grouped-effect row preserved structurally; descriptor identity not yet recovered"
|
"recovered locomotive availability descriptor family remains parity-only until per-locomotive identity is grounded"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -90,7 +90,7 @@
|
||||||
"executable_import_ready": false,
|
"executable_import_ready": false,
|
||||||
"notes": [
|
"notes": [
|
||||||
"decoded from grounded real 0x4e9a row framing",
|
"decoded from grounded real 0x4e9a row framing",
|
||||||
"grouped row preserved structurally but still unmapped in the checked-in descriptor table"
|
"recovered locomotives-page descriptor band is now checked in, but this scalar family still has no executable runtime landing surface"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"fixture_id": "packed-event-world-locomotive-policy-save-slice-fixture",
|
||||||
|
"source": {
|
||||||
|
"kind": "captured-runtime",
|
||||||
|
"description": "Fixture proving recovered locomotive policy descriptors import and execute through the ordinary runtime path."
|
||||||
|
},
|
||||||
|
"state_save_slice_path": "packed-event-world-locomotive-policy-save-slice.json",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"kind": "service_trigger_kind",
|
||||||
|
"trigger_kind": 6
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_summary": {
|
||||||
|
"packed_event_collection_present": true,
|
||||||
|
"packed_event_record_count": 1,
|
||||||
|
"packed_event_decoded_record_count": 1,
|
||||||
|
"packed_event_imported_runtime_record_count": 1,
|
||||||
|
"event_runtime_record_count": 1,
|
||||||
|
"packed_event_blocked_unmapped_world_descriptor_count": 0,
|
||||||
|
"total_event_record_service_count": 1,
|
||||||
|
"total_trigger_dispatch_count": 1
|
||||||
|
},
|
||||||
|
"expected_state_fragment": {
|
||||||
|
"world_flags": {
|
||||||
|
"world.all_steam_locos_available": true,
|
||||||
|
"world.all_diesel_locos_available": false,
|
||||||
|
"world.all_electric_locos_available": true
|
||||||
|
},
|
||||||
|
"packed_event_collection": {
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"import_outcome": "imported",
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_steam_locos_available",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_diesel_locos_available",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_electric_locos_available",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
{
|
||||||
|
"format_version": 1,
|
||||||
|
"save_slice_id": "packed-event-world-locomotive-policy-save-slice",
|
||||||
|
"source": {
|
||||||
|
"description": "Tracked save-slice document proving recovered locomotive policy descriptors import and execute as keyed world flags.",
|
||||||
|
"original_save_filename": "captured-world-locomotive-policy.gms",
|
||||||
|
"original_save_sha256": "world-locomotive-policy-sample-sha256",
|
||||||
|
"notes": [
|
||||||
|
"tracked as JSON save-slice document rather than raw .smp",
|
||||||
|
"recovered locomotives-page policy descriptors 454..456 now import through checked-in keyed world-flag metadata"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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,
|
||||||
|
"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": 32512,
|
||||||
|
"records_tag_offset": 32768,
|
||||||
|
"close_tag_offset": 33536,
|
||||||
|
"packed_state_version": 1001,
|
||||||
|
"packed_state_version_hex": "0x000003e9",
|
||||||
|
"live_id_bound": 61,
|
||||||
|
"live_record_count": 1,
|
||||||
|
"live_entry_ids": [61],
|
||||||
|
"decoded_record_count": 1,
|
||||||
|
"imported_runtime_record_count": 1,
|
||||||
|
"records": [
|
||||||
|
{
|
||||||
|
"record_index": 0,
|
||||||
|
"live_entry_id": 61,
|
||||||
|
"payload_offset": 32832,
|
||||||
|
"payload_len": 176,
|
||||||
|
"decode_status": "executable",
|
||||||
|
"payload_family": "real_packed_v1",
|
||||||
|
"trigger_kind": 6,
|
||||||
|
"one_shot": false,
|
||||||
|
"compact_control": {
|
||||||
|
"mode_byte_0x7ef": 6,
|
||||||
|
"primary_selector_0x7f0": 0,
|
||||||
|
"grouped_mode_0x7f4": 2,
|
||||||
|
"one_shot_header_0x7f5": 0,
|
||||||
|
"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": [3, 0, 0, 0],
|
||||||
|
"grouped_effect_rows": [
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 0,
|
||||||
|
"descriptor_id": 454,
|
||||||
|
"descriptor_label": "All Steam Locos Avail.",
|
||||||
|
"target_mask_bits": 8,
|
||||||
|
"parameter_family": "world_flag_toggle",
|
||||||
|
"opcode": 0,
|
||||||
|
"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": "bool_toggle",
|
||||||
|
"semantic_family": "bool_toggle",
|
||||||
|
"semantic_preview": "Set All Steam Locos Avail. to TRUE",
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 1,
|
||||||
|
"descriptor_id": 455,
|
||||||
|
"descriptor_label": "All Diesel Locos Avail.",
|
||||||
|
"target_mask_bits": 8,
|
||||||
|
"parameter_family": "world_flag_toggle",
|
||||||
|
"opcode": 0,
|
||||||
|
"raw_scalar_value": 0,
|
||||||
|
"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": "bool_toggle",
|
||||||
|
"semantic_family": "bool_toggle",
|
||||||
|
"semantic_preview": "Set All Diesel Locos Avail. to FALSE",
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"group_index": 0,
|
||||||
|
"row_index": 2,
|
||||||
|
"descriptor_id": 456,
|
||||||
|
"descriptor_label": "All Electric Locos Avail.",
|
||||||
|
"target_mask_bits": 8,
|
||||||
|
"parameter_family": "world_flag_toggle",
|
||||||
|
"opcode": 0,
|
||||||
|
"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": "bool_toggle",
|
||||||
|
"semantic_family": "bool_toggle",
|
||||||
|
"semantic_preview": "Set All Electric Locos Avail. to TRUE",
|
||||||
|
"locomotive_name": null,
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decoded_conditions": [],
|
||||||
|
"decoded_actions": [
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_steam_locos_available",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_diesel_locos_available",
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "set_world_flag",
|
||||||
|
"key": "world.all_electric_locos_available",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"executable_import_ready": true,
|
||||||
|
"notes": [
|
||||||
|
"recovered locomotives-page policy descriptor batch now imports as keyed world flags"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
"whole-game locomotive policy effect sample"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue