Close EventEffects semantic descriptor frontier

This commit is contained in:
Jan Petykiewicz 2026-04-16 20:20:41 -07:00
commit 51a7bbd756
18 changed files with 5432 additions and 175 deletions

View file

@ -4476,6 +4476,9 @@ mod tests {
let world_scalar_executable_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-executable-save-slice-fixture.json",
);
let world_scalar_override_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-override-save-slice-fixture.json",
);
let world_scalar_condition_fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(
"../../fixtures/runtime/packed-event-world-scalar-condition-save-slice-fixture.json",
);
@ -4585,6 +4588,8 @@ mod tests {
.expect("save-slice-backed recovered scalar-band parity fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_executable_fixture)
.expect("save-slice-backed executable world-scalar fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_override_fixture)
.expect("save-slice-backed world-scalar override fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_fixture)
.expect("save-slice-backed executable world-scalar condition fixture should summarize");
run_runtime_summarize_fixture(&world_scalar_condition_parity_fixture)

View file

@ -190,6 +190,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
},
@ -377,6 +378,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
},

View file

@ -148,6 +148,10 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub packed_event_blocked_shell_owned_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_evidence_blocked_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_world_descriptor_count: Option<usize>,
@ -184,6 +188,8 @@ pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub cargo_production_override_count: Option<usize>,
#[serde(default)]
pub world_scalar_override_count: Option<usize>,
#[serde(default)]
pub special_condition_count: Option<usize>,
#[serde(default)]
pub enabled_special_condition_count: Option<usize>,
@ -761,6 +767,22 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(count) = self.packed_event_blocked_evidence_blocked_descriptor_count {
if actual.packed_event_blocked_evidence_blocked_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_evidence_blocked_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_evidence_blocked_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_variant_or_scope_blocked_descriptor_count {
if actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_variant_or_scope_blocked_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_unmapped_real_descriptor_count {
if actual.packed_event_blocked_unmapped_real_descriptor_count != count {
mismatches.push(format!(
@ -905,6 +927,14 @@ impl ExpectedRuntimeSummary {
));
}
}
if let Some(count) = self.world_scalar_override_count {
if actual.world_scalar_override_count != count {
mismatches.push(format!(
"world_scalar_override_count mismatch: expected {count}, got {}",
actual.world_scalar_override_count
));
}
}
if let Some(count) = self.special_condition_count {
if actual.special_condition_count != count {
mismatches.push(format!(

View file

@ -31,6 +31,7 @@ pub const REQUIRED_EXPORTS: &[&str] = &[
"artifacts/exports/rt3-1.06/pending-template-store-record-kinds.csv",
"artifacts/exports/rt3-1.06/pending-template-store-management.md",
"artifacts/exports/rt3-1.06/event-effects-table.json",
"artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json",
];
pub const REQUIRED_ATLAS_HEADINGS: &[&str] = &[

View file

@ -106,6 +106,7 @@ struct SaveSliceProjection {
cargo_catalog: Option<Vec<RuntimeCargoCatalogEntry>>,
named_locomotive_cost: BTreeMap<String, u32>,
cargo_production_overrides: BTreeMap<u32, u32>,
world_scalar_overrides: BTreeMap<String, i64>,
special_conditions: BTreeMap<String, u32>,
}
@ -277,6 +278,7 @@ pub fn project_save_slice_to_runtime_state_import(
named_locomotive_availability: projection.named_locomotive_availability,
named_locomotive_cost: projection.named_locomotive_cost,
cargo_production_overrides: projection.cargo_production_overrides,
world_scalar_overrides: projection.world_scalar_overrides,
special_conditions: projection.special_conditions,
service_state: RuntimeServiceState::default(),
};
@ -364,6 +366,7 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
named_locomotive_availability: projection.named_locomotive_availability,
named_locomotive_cost: base_state.named_locomotive_cost.clone(),
cargo_production_overrides: base_state.cargo_production_overrides.clone(),
world_scalar_overrides: base_state.world_scalar_overrides.clone(),
special_conditions: projection.special_conditions,
service_state: base_state.service_state.clone(),
};
@ -872,6 +875,7 @@ fn project_save_slice_components(
let named_locomotive_cost = BTreeMap::new();
let cargo_production_overrides = BTreeMap::new();
let world_scalar_overrides = BTreeMap::new();
let mut packed_event_context = company_context.clone();
if has_company_projection {
@ -948,6 +952,7 @@ fn project_save_slice_components(
cargo_catalog,
named_locomotive_cost,
cargo_production_overrides,
world_scalar_overrides,
special_conditions,
})
}
@ -1316,6 +1321,10 @@ fn lower_contextual_real_grouped_effects(
if real_grouped_row_is_unsupported_chairman_target_scope(row) {
return Err(ImportBlocker::ChairmanTargetScope);
}
if let Some(effect) = lower_contextual_world_scalar_override_effect(row)? {
effects.push(effect);
continue;
}
if let Some(effect) = lower_contextual_cargo_production_effect(row)? {
effects.push(effect);
continue;
@ -1347,6 +1356,28 @@ fn lower_contextual_real_grouped_effects(
Ok(effects)
}
fn lower_contextual_world_scalar_override_effect(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> Result<Option<RuntimeEffect>, ImportBlocker> {
if row.parameter_family.as_deref() != Some("world_scalar_override") {
return Ok(None);
}
if row.row_shape != "scalar_assignment" {
return Ok(None);
}
let Some(key) = row
.descriptor_label
.as_deref()
.map(crate::smp::runtime_world_scalar_key_from_label)
else {
return Ok(None);
};
Ok(Some(RuntimeEffect::SetWorldScalarOverride {
key,
value: i64::from(row.raw_scalar_value),
}))
}
fn lower_contextual_locomotive_availability_effect(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
company_context: &ImportRuntimeContext,
@ -1564,6 +1595,12 @@ fn lower_condition_targets_in_effect(
key: key.clone(),
value: *value,
},
RuntimeEffect::SetWorldScalarOverride { key, value } => {
RuntimeEffect::SetWorldScalarOverride {
key: key.clone(),
value: *value,
}
}
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value }
}
@ -2346,6 +2383,12 @@ fn smp_runtime_effect_to_runtime_effect(
value: *value,
})
}
RuntimeEffect::SetWorldScalarOverride { key, value } => {
Ok(RuntimeEffect::SetWorldScalarOverride {
key: key.clone(),
value: *value,
})
}
RuntimeEffect::SetCargoProductionSlot { slot, value } => {
Ok(RuntimeEffect::SetCargoProductionSlot {
slot: *slot,
@ -2690,6 +2733,27 @@ fn determine_packed_event_import_outcome(
{
return "blocked_shell_owned_descriptor".to_string();
}
if record
.grouped_effect_rows
.iter()
.any(real_grouped_row_is_evidence_blocked_descriptor_family)
{
return "blocked_evidence_blocked_descriptor".to_string();
}
if record
.grouped_effect_rows
.iter()
.any(real_grouped_row_is_variant_or_scope_blocked_descriptor_family)
{
return "blocked_variant_or_scope_blocked_descriptor".to_string();
}
if record
.grouped_effect_rows
.iter()
.any(real_grouped_row_is_unsupported_executable_descriptor_variant)
{
return "blocked_variant_or_scope_blocked_descriptor".to_string();
}
if record
.grouped_effect_rows
.iter()
@ -2788,9 +2852,47 @@ fn real_grouped_row_is_world_state_family(
fn real_grouped_row_is_shell_owned_descriptor_family(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> bool {
real_grouped_row_has_runtime_status(row, "shell_owned")
}
fn real_grouped_row_is_evidence_blocked_descriptor_family(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> bool {
real_grouped_row_has_runtime_status(row, "evidence_blocked")
}
fn real_grouped_row_is_variant_or_scope_blocked_descriptor_family(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> bool {
real_grouped_row_has_runtime_status(row, "variant_or_scope_blocked")
}
fn real_grouped_row_has_runtime_status(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
status: &str,
) -> bool {
crate::smp::grouped_effect_descriptor_runtime_status_name(row.descriptor_id)
.is_some_and(|status| status == "shell_owned")
.is_some_and(|runtime_status| runtime_status == status)
}
fn real_grouped_row_is_unsupported_executable_descriptor_variant(
row: &SmpLoadedPackedEventGroupedEffectRowSummary,
) -> bool {
if !real_grouped_row_has_runtime_status(row, "executable") {
return false;
}
match row.descriptor_id {
1 => !(row.opcode == 8 && row.row_shape == "multivalue_scalar"),
2 => !(row.opcode == 8 && row.row_shape == "multivalue_scalar"),
8 | 108 | 109 | 122 => row.row_shape != "scalar_assignment",
13 | 14 => !(row.row_shape == "bool_toggle" && row.raw_scalar_value != 0),
56 | 57 => row.row_shape != "scalar_assignment",
_ => {
row.parameter_family.as_deref() == Some("world_scalar_override")
&& row.row_shape != "scalar_assignment"
}
}
}
fn packed_record_company_target_import_blocker(
@ -2980,6 +3082,7 @@ fn runtime_effect_uses_condition_true_company(effect: &RuntimeEffect) -> bool {
.iter()
.any(runtime_effect_uses_condition_true_company),
RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetWorldScalarOverride { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetPlayerCash { .. }
@ -3093,6 +3196,7 @@ fn runtime_effect_company_target_import_blocker(
runtime_effect_company_target_import_blocker(nested, company_context)
}),
RuntimeEffect::SetWorldFlag { .. }
| RuntimeEffect::SetWorldScalarOverride { .. }
| RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. }
| RuntimeEffect::SetCandidateAvailability { .. }
@ -3449,6 +3553,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
}
@ -6634,6 +6739,7 @@ mod tests {
]),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -7039,6 +7145,7 @@ mod tests {
("Locomotive 101".to_string(), 200000),
]),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -7211,7 +7318,7 @@ mod tests {
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_unmapped_world_descriptor")
Some("blocked_evidence_blocked_descriptor")
);
}
@ -7439,6 +7546,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -8207,7 +8315,7 @@ mod tests {
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_unmapped_real_descriptor")
Some("blocked_variant_or_scope_blocked_descriptor")
);
}
@ -8295,7 +8403,7 @@ mod tests {
.packed_event_collection
.as_ref()
.and_then(|summary| summary.records[0].import_outcome.as_deref()),
Some("blocked_unmapped_real_descriptor")
Some("blocked_variant_or_scope_blocked_descriptor")
);
}
@ -9713,6 +9821,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -9886,6 +9995,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -11574,6 +11684,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState {
periodic_boundary_calls: 9,
@ -11758,6 +11869,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
},

View file

@ -110,6 +110,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
},

View file

@ -467,6 +467,10 @@ pub enum RuntimeEffect {
slot: u32,
value: u32,
},
SetWorldScalarOverride {
key: String,
value: i64,
},
SetTerritoryAccessCost {
value: u32,
},
@ -842,6 +846,8 @@ pub struct RuntimeState {
#[serde(default)]
pub cargo_production_overrides: BTreeMap<u32, u32>,
#[serde(default)]
pub world_scalar_overrides: BTreeMap<String, i64>,
#[serde(default)]
pub special_conditions: BTreeMap<String, u32>,
#[serde(default)]
pub service_state: RuntimeServiceState,
@ -1489,6 +1495,11 @@ impl RuntimeState {
));
}
}
for key in self.world_scalar_overrides.keys() {
if key.trim().is_empty() {
return Err("world_scalar_overrides contains an empty key".to_string());
}
}
for key in self.special_conditions.keys() {
if key.trim().is_empty() {
return Err("special_conditions contains an empty key".to_string());
@ -1512,6 +1523,11 @@ fn validate_runtime_effect(
return Err("key must not be empty".to_string());
}
}
RuntimeEffect::SetWorldScalarOverride { key, .. } => {
if key.trim().is_empty() {
return Err("key must not be empty".to_string());
}
}
RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
| RuntimeEffect::SetEconomicStatusCode { .. } => {}
RuntimeEffect::SetCompanyCash { target, .. }
@ -1901,6 +1917,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1964,6 +1981,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2031,6 +2049,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2108,6 +2127,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2210,6 +2230,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2264,6 +2285,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2318,6 +2340,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2389,6 +2412,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2450,6 +2474,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2515,6 +2540,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2576,6 +2602,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2643,6 +2670,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2704,6 +2732,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2765,6 +2794,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2819,6 +2849,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -2883,6 +2914,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};

View file

@ -141,20 +141,19 @@ enum RealGroupedEffectRuntimeStatus {
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
struct CheckedInEventEffectsTableArtifact {
descriptors: Vec<CheckedInEventEffectDescriptorRow>,
struct CheckedInEventEffectsSemanticCatalogArtifact {
descriptors: Vec<CheckedInEventEffectSemanticRow>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
struct CheckedInEventEffectDescriptorRow {
struct CheckedInEventEffectSemanticRow {
descriptor_id: u32,
selector_order: f32,
target_mask_bits: u8,
label_id: u32,
label: String,
signature_byte_0x63: u8,
signature_byte_0x64: u8,
signature_hex_0x63_0x6d: String,
target_mask_bits: u8,
parameter_family: String,
runtime_key: Option<String>,
runtime_status: String,
executable_in_runtime: bool,
}
const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetadata; 12] = [
@ -281,10 +280,10 @@ fn checked_in_event_effect_descriptor_rows()
-> &'static BTreeMap<u32, RealGroupedEffectDescriptorMetadata> {
static ROWS: OnceLock<BTreeMap<u32, RealGroupedEffectDescriptorMetadata>> = OnceLock::new();
ROWS.get_or_init(|| {
let artifact: CheckedInEventEffectsTableArtifact = serde_json::from_str(include_str!(
"../../../artifacts/exports/rt3-1.06/event-effects-table.json"
))
.expect("checked-in event-effects artifact should parse");
let artifact: CheckedInEventEffectsSemanticCatalogArtifact = serde_json::from_str(
include_str!("../../../artifacts/exports/rt3-1.06/event-effects-semantic-catalog.json"),
)
.expect("checked-in event-effects semantic catalog should parse");
artifact
.descriptors
.into_iter()
@ -299,14 +298,20 @@ fn checked_in_event_effect_descriptor_rows()
}
fn checked_in_event_effect_descriptor_metadata(
row: CheckedInEventEffectDescriptorRow,
row: CheckedInEventEffectSemanticRow,
) -> RealGroupedEffectDescriptorMetadata {
let label = Box::leak(row.label.clone().into_boxed_str()) as &'static str;
let (parameter_family, runtime_key, runtime_status, executable_in_runtime) =
classify_checked_in_event_effect_descriptor(&row, label);
debug_assert!(!row.signature_hex_0x63_0x6d.is_empty());
debug_assert!(row.label_id <= u16::MAX as u32);
let _ = row.selector_order;
let parameter_family = Box::leak(row.parameter_family.into_boxed_str()) as &'static str;
let runtime_key = row
.runtime_key
.map(|key| Box::leak(key.into_boxed_str()) as &'static str);
let runtime_status = match row.runtime_status.as_str() {
"executable" => RealGroupedEffectRuntimeStatus::Executable,
"shell_owned" => RealGroupedEffectRuntimeStatus::ShellOwned,
"evidence_blocked" => RealGroupedEffectRuntimeStatus::EvidenceBlocked,
"variant_or_scope_blocked" => RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked,
other => panic!("unknown checked-in event-effect runtime status {other}"),
};
RealGroupedEffectDescriptorMetadata {
descriptor_id: row.descriptor_id,
label,
@ -314,141 +319,10 @@ fn checked_in_event_effect_descriptor_metadata(
parameter_family,
runtime_key,
runtime_status,
executable_in_runtime,
executable_in_runtime: row.executable_in_runtime,
}
}
fn classify_checked_in_event_effect_descriptor(
row: &CheckedInEventEffectDescriptorRow,
label: &'static str,
) -> (
&'static str,
Option<&'static str>,
RealGroupedEffectRuntimeStatus,
bool,
) {
let descriptor_id = row.descriptor_id;
match descriptor_id {
4..=7 => {
return (
"scenario_outcome_shell_action",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
10 | 11 | 12 | 23 => {
return (
"company_confiscation_variant",
None,
RealGroupedEffectRuntimeStatus::VariantOrScopeBlocked,
false,
);
}
17..=21 => {
return (
"company_or_territory_destruction_variant",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
24 => {
return (
"control_transfer_shell_action",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
56 => {
return (
"company_governance_scalar",
None,
RealGroupedEffectRuntimeStatus::Executable,
true,
);
}
57 => {
return (
"company_governance_scalar",
None,
RealGroupedEffectRuntimeStatus::Executable,
true,
);
}
58 => {
return (
"company_finance_shell_scalar",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
_ => {}
}
if row.signature_byte_0x63 == 0 && row.signature_byte_0x64 == 0x8f {
return (
"runtime_variable_scalar",
None,
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
false,
);
}
if row.target_mask_bits == 0x0b && label == "Stock Prices" {
return (
"company_finance_shell_scalar",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
if label.contains("Cost")
|| label.contains("Revenue")
|| label.contains("Speed")
|| label.contains("Reliability")
|| label.contains("Acceleration")
|| label.contains("Pulling Power")
|| label.contains("Usage Rate")
|| label.contains("Maintenance")
{
return (
"world_scalar_economy_or_locomotive",
None,
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
false,
);
}
if label.contains("Earthquake") || label.contains("Storm") {
return (
"world_disaster_scalar",
None,
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
false,
);
}
if label.contains("Add Building") {
return (
"world_building_spawn",
None,
RealGroupedEffectRuntimeStatus::ShellOwned,
false,
);
}
(
"recovered_effect_table_descriptor",
None,
RealGroupedEffectRuntimeStatus::EvidenceBlocked,
false,
)
}
pub(crate) fn grouped_effect_descriptor_runtime_status_name(
descriptor_id: u32,
) -> Option<&'static str> {
@ -4101,7 +3975,27 @@ fn runtime_world_flag_key(
})
}
fn runtime_world_flag_key_from_label(label: &str) -> String {
pub(crate) fn runtime_world_flag_key_from_label(label: &str) -> String {
normalize_runtime_world_key(label)
}
fn runtime_world_scalar_key(
descriptor_metadata: RealGroupedEffectDescriptorMetadata,
) -> Option<String> {
descriptor_metadata
.runtime_key
.map(str::to_string)
.or_else(|| {
(descriptor_metadata.parameter_family == "world_scalar_override")
.then(|| normalize_runtime_world_key(descriptor_metadata.label))
})
}
pub(crate) fn runtime_world_scalar_key_from_label(label: &str) -> String {
normalize_runtime_world_key(label)
}
fn normalize_runtime_world_key(label: &str) -> String {
let mut key = String::with_capacity(label.len() + 6);
key.push_str("world.");
let mut last_was_underscore = false;
@ -4140,6 +4034,9 @@ fn derive_real_grouped_target_subject(
if row.parameter_family.as_deref() == Some("company_governance_scalar") {
return Some(RealGroupedTargetSubject::Company);
}
if row.parameter_family.as_deref() == Some("world_scalar_override") {
return Some(RealGroupedTargetSubject::WholeGame);
}
match row.target_mask_bits {
Some(0x08) => Some(RealGroupedTargetSubject::WholeGame),
Some(0x01) => Some(RealGroupedTargetSubject::Company),
@ -4353,6 +4250,16 @@ fn decode_real_grouped_effect_action(
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "world_scalar_override"
&& row.row_shape == "scalar_assignment"
{
return Some(RuntimeEffect::SetWorldScalarOverride {
key: runtime_world_scalar_key(descriptor_metadata)?,
value: i64::from(row.raw_scalar_value),
});
}
if descriptor_metadata.executable_in_runtime
&& descriptor_metadata.parameter_family == "cargo_production_scalar"
&& row.row_shape == "scalar_assignment"
@ -4657,6 +4564,7 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
| RuntimeEffect::SetNamedLocomotiveAvailabilityValue { .. }
| RuntimeEffect::SetNamedLocomotiveCost { .. }
| RuntimeEffect::SetCargoProductionSlot { .. }
| RuntimeEffect::SetWorldScalarOverride { .. }
| RuntimeEffect::SetTerritoryAccessCost { .. }
| RuntimeEffect::SetSpecialCondition { .. }
| RuntimeEffect::ConfiscateCompanyAssets { .. }

View file

@ -313,6 +313,9 @@ fn apply_runtime_effects(
RuntimeEffect::SetWorldFlag { key, value } => {
state.world_flags.insert(key.clone(), *value);
}
RuntimeEffect::SetWorldScalarOverride { key, value } => {
state.world_scalar_overrides.insert(key.clone(), *value);
}
RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
state.world_restore.limited_track_building_amount = Some(*value);
}
@ -1559,6 +1562,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
}
@ -1912,6 +1916,10 @@ mod tests {
has_fired: false,
conditions: Vec::new(),
effects: vec![
RuntimeEffect::SetWorldScalarOverride {
key: "world.build_stations_cost".to_string(),
value: 350000,
},
RuntimeEffect::SetCargoProductionSlot {
slot: 1,
value: 125,
@ -1928,9 +1936,15 @@ mod tests {
)
.expect("world scalar override effects should succeed");
assert_eq!(
state
.world_scalar_overrides
.get("world.build_stations_cost"),
Some(&350000)
);
assert_eq!(state.cargo_production_overrides.get(&1), Some(&125));
assert_eq!(state.world_restore.territory_access_cost, Some(750000));
assert_eq!(result.service_events[0].applied_effect_count, 2);
assert_eq!(result.service_events[0].applied_effect_count, 3);
}
#[test]

View file

@ -71,6 +71,8 @@ pub struct RuntimeSummary {
pub packed_event_blocked_unmapped_world_condition_count: usize,
pub packed_event_blocked_missing_compact_control_count: usize,
pub packed_event_blocked_shell_owned_descriptor_count: usize,
pub packed_event_blocked_evidence_blocked_descriptor_count: usize,
pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: usize,
pub packed_event_blocked_unmapped_real_descriptor_count: usize,
pub packed_event_blocked_unmapped_world_descriptor_count: usize,
pub packed_event_blocked_territory_access_variant_count: usize,
@ -89,6 +91,7 @@ pub struct RuntimeSummary {
pub zero_named_locomotive_availability_count: usize,
pub named_locomotive_cost_count: usize,
pub cargo_production_override_count: usize,
pub world_scalar_override_count: usize,
pub special_condition_count: usize,
pub enabled_special_condition_count: usize,
pub save_profile_kind: Option<String>,
@ -511,6 +514,34 @@ impl RuntimeSummary {
.count()
})
.unwrap_or(0),
packed_event_blocked_evidence_blocked_descriptor_count: state
.packed_event_collection
.as_ref()
.map(|summary| {
summary
.records
.iter()
.filter(|record| {
record.import_outcome.as_deref()
== Some("blocked_evidence_blocked_descriptor")
})
.count()
})
.unwrap_or(0),
packed_event_blocked_variant_or_scope_blocked_descriptor_count: state
.packed_event_collection
.as_ref()
.map(|summary| {
summary
.records
.iter()
.filter(|record| {
record.import_outcome.as_deref()
== Some("blocked_variant_or_scope_blocked_descriptor")
})
.count()
})
.unwrap_or(0),
packed_event_blocked_unmapped_real_descriptor_count: state
.packed_event_collection
.as_ref()
@ -676,6 +707,7 @@ impl RuntimeSummary {
.count(),
named_locomotive_cost_count: state.named_locomotive_cost.len(),
cargo_production_override_count: state.cargo_production_overrides.len(),
world_scalar_override_count: state.world_scalar_overrides.len(),
special_condition_count: state.special_conditions.len(),
enabled_special_condition_count: state
.special_conditions
@ -903,6 +935,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1019,6 +1052,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1072,6 +1106,7 @@ mod tests {
]),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1117,6 +1152,7 @@ mod tests {
("GP7".to_string(), 175000),
]),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1160,6 +1196,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::from([(1, 125), (2, 250)]),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1265,6 +1302,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1348,6 +1386,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};
@ -1427,6 +1466,7 @@ mod tests {
named_locomotive_availability: BTreeMap::new(),
named_locomotive_cost: BTreeMap::new(),
cargo_production_overrides: BTreeMap::new(),
world_scalar_overrides: BTreeMap::new(),
special_conditions: BTreeMap::new(),
service_state: RuntimeServiceState::default(),
};