Implement world-scalar packed event conditions
This commit is contained in:
parent
b060c42fa2
commit
3f2632e330
12 changed files with 1541 additions and 8 deletions
|
|
@ -240,6 +240,11 @@ enum RealOrdinaryConditionMetric {
|
|||
enum RealWorldConditionKind {
|
||||
SpecialCondition { label: &'static str },
|
||||
CandidateAvailability,
|
||||
NamedLocomotiveAvailability,
|
||||
NamedLocomotiveCost,
|
||||
CargoProductionTotal,
|
||||
LimitedTrackBuildingAmount,
|
||||
TerritoryAccessCost,
|
||||
EconomicStatus,
|
||||
WorldFlag { key: &'static str },
|
||||
}
|
||||
|
|
@ -258,8 +263,13 @@ struct RealOrdinaryConditionMetadata {
|
|||
}
|
||||
|
||||
const REAL_CANDIDATE_AVAILABILITY_CONDITION_TEMPLATE_ID: i32 = 435;
|
||||
const REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID: i32 = 2422;
|
||||
const REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID: i32 = 2423;
|
||||
const REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID: i32 = 2418;
|
||||
const REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID: i32 = 2547;
|
||||
const REAL_TERRITORY_ACCESS_COST_CONDITION_ID: i32 = 1516;
|
||||
|
||||
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [
|
||||
const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 29] = [
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: 1802,
|
||||
label: "Current Cash",
|
||||
|
|
@ -419,6 +429,35 @@ const REAL_ORDINARY_CONDITION_METADATA: [RealOrdinaryConditionMetadata; 24] = [
|
|||
label: "%1 Avail.",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CandidateAvailability),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
|
||||
label: "Unknown Loco Available",
|
||||
kind: RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
|
||||
label: "Unknown Loco Cost",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
|
||||
label: "All Cargo Production",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
|
||||
label: "Limited Track Building Amount",
|
||||
kind: RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
|
||||
label: "Access Rights Cost:",
|
||||
kind: RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost),
|
||||
},
|
||||
RealOrdinaryConditionMetadata {
|
||||
raw_condition_id: 2350,
|
||||
label: "Economic Status",
|
||||
|
|
@ -2526,6 +2565,17 @@ fn parse_real_condition_row_summary(
|
|||
.to_string(),
|
||||
);
|
||||
}
|
||||
if ordinary_metadata.is_some_and(|metadata| {
|
||||
matches!(
|
||||
metadata.kind,
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability
|
||||
| RealWorldConditionKind::NamedLocomotiveCost
|
||||
)
|
||||
) && candidate_name.is_none()
|
||||
}) {
|
||||
notes.push("named locomotive condition row is missing its side-string binding".to_string());
|
||||
}
|
||||
Some(SmpLoadedPackedEventConditionRowSummary {
|
||||
row_index,
|
||||
raw_condition_id,
|
||||
|
|
@ -2645,6 +2695,27 @@ fn real_ordinary_condition_metric_label(
|
|||
None => "Candidate Availability".to_string(),
|
||||
}
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
) => match candidate_name {
|
||||
Some(name) => format!("Named Locomotive Availability: {name}"),
|
||||
None => "Named Locomotive Availability".to_string(),
|
||||
},
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => {
|
||||
match candidate_name {
|
||||
Some(name) => format!("Named Locomotive Cost: {name}"),
|
||||
None => "Named Locomotive Cost".to_string(),
|
||||
}
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
|
||||
"Cargo Production Total".to_string()
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
) => "Limited Track Building Amount".to_string(),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
|
||||
"Territory Access Cost".to_string()
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||
"Economic Status".to_string()
|
||||
}
|
||||
|
|
@ -2662,6 +2733,13 @@ fn real_ordinary_condition_semantic_family(
|
|||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::WorldFlag { .. }) => {
|
||||
"world_flag_equals"
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability
|
||||
| RealWorldConditionKind::NamedLocomotiveCost
|
||||
| RealWorldConditionKind::CargoProductionTotal
|
||||
| RealWorldConditionKind::LimitedTrackBuildingAmount
|
||||
| RealWorldConditionKind::TerritoryAccessCost,
|
||||
) => "world_scalar_threshold",
|
||||
RealOrdinaryConditionKind::WorldState(_) => "world_state_threshold",
|
||||
}
|
||||
}
|
||||
|
|
@ -2868,6 +2946,32 @@ fn decode_real_condition_row(
|
|||
comparator,
|
||||
value,
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::NamedLocomotiveAvailability,
|
||||
) => row.candidate_name.as_ref().map(|name| {
|
||||
RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: name.clone(),
|
||||
comparator,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::NamedLocomotiveCost) => row
|
||||
.candidate_name
|
||||
.as_ref()
|
||||
.map(|name| RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: name.clone(),
|
||||
comparator,
|
||||
value,
|
||||
}),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::CargoProductionTotal) => {
|
||||
Some(RuntimeCondition::CargoProductionTotalThreshold { comparator, value })
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(
|
||||
RealWorldConditionKind::LimitedTrackBuildingAmount,
|
||||
) => Some(RuntimeCondition::LimitedTrackBuildingAmountThreshold { comparator, value }),
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::TerritoryAccessCost) => {
|
||||
Some(RuntimeCondition::TerritoryAccessCostThreshold { comparator, value })
|
||||
}
|
||||
RealOrdinaryConditionKind::WorldState(RealWorldConditionKind::EconomicStatus) => {
|
||||
Some(RuntimeCondition::EconomicStatusCodeThreshold { comparator, value })
|
||||
}
|
||||
|
|
@ -3655,6 +3759,11 @@ fn runtime_condition_supported_for_save_import(condition: &RuntimeCondition) ->
|
|||
| RuntimeCondition::CompanyTerritoryNumericThreshold { .. }
|
||||
| RuntimeCondition::SpecialConditionThreshold { .. }
|
||||
| RuntimeCondition::CandidateAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveAvailabilityThreshold { .. }
|
||||
| RuntimeCondition::NamedLocomotiveCostThreshold { .. }
|
||||
| RuntimeCondition::CargoProductionTotalThreshold { .. }
|
||||
| RuntimeCondition::LimitedTrackBuildingAmountThreshold { .. }
|
||||
| RuntimeCondition::TerritoryAccessCostThreshold { .. }
|
||||
| RuntimeCondition::EconomicStatusCodeThreshold { .. }
|
||||
| RuntimeCondition::WorldFlagEquals { .. } => true,
|
||||
}
|
||||
|
|
@ -9431,6 +9540,224 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_named_locomotive_availability_threshold_from_checked_in_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(
|
||||
REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID,
|
||||
4,
|
||||
42,
|
||||
Some("Big Boy"),
|
||||
);
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
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: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&[condition_row],
|
||||
[&[], &[], &[], &[]],
|
||||
);
|
||||
|
||||
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].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Named Locomotive Availability: Big Boy")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.semantic_family
|
||||
.as_deref(),
|
||||
Some("world_scalar_threshold")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![RuntimeCondition::NamedLocomotiveAvailabilityThreshold {
|
||||
name: "Big Boy".to_string(),
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 42,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_named_locomotive_cost_threshold_from_checked_in_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(
|
||||
REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID,
|
||||
0,
|
||||
250000,
|
||||
Some("Locomotive 1"),
|
||||
);
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
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: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&[condition_row],
|
||||
[&[], &[], &[], &[]],
|
||||
);
|
||||
|
||||
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].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Named Locomotive Cost: Locomotive 1")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![RuntimeCondition::NamedLocomotiveCostThreshold {
|
||||
name: "Locomotive 1".to_string(),
|
||||
comparator: RuntimeConditionComparator::Ge,
|
||||
value: 250000,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_world_scalar_thresholds_from_checked_in_metadata() {
|
||||
let condition_rows = vec![
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID,
|
||||
0,
|
||||
200,
|
||||
None,
|
||||
),
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID,
|
||||
4,
|
||||
18,
|
||||
None,
|
||||
),
|
||||
build_real_condition_row_with_threshold(
|
||||
REAL_TERRITORY_ACCESS_COST_CONDITION_ID,
|
||||
4,
|
||||
750000,
|
||||
None,
|
||||
),
|
||||
];
|
||||
let record_body = build_real_event_record(
|
||||
[b"World", b"", b"", b"", b"", b""],
|
||||
Some(RealCompactControlSpec {
|
||||
mode_byte_0x7ef: 7,
|
||||
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: [0, 0, 0, 0],
|
||||
summary_toggle_0x800: 1,
|
||||
grouped_territory_selectors_0x80f: [-1, -1, -1, -1],
|
||||
}),
|
||||
&condition_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].standalone_condition_rows[0]
|
||||
.metric
|
||||
.as_deref(),
|
||||
Some("Cargo Production Total")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].standalone_condition_rows[0]
|
||||
.semantic_family
|
||||
.as_deref(),
|
||||
Some("world_scalar_threshold")
|
||||
);
|
||||
assert_eq!(
|
||||
summary.records[0].decoded_conditions,
|
||||
vec![
|
||||
RuntimeCondition::CargoProductionTotalThreshold {
|
||||
comparator: RuntimeConditionComparator::Ge,
|
||||
value: 200,
|
||||
},
|
||||
RuntimeCondition::LimitedTrackBuildingAmountThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 18,
|
||||
},
|
||||
RuntimeCondition::TerritoryAccessCostThreshold {
|
||||
comparator: RuntimeConditionComparator::Eq,
|
||||
value: 750000,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_real_world_flag_condition_from_checked_in_world_condition_metadata() {
|
||||
let condition_row = build_real_condition_row_with_threshold(2535, 4, 1, None);
|
||||
|
|
@ -9492,6 +9819,31 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_checked_in_world_scalar_condition_metadata() {
|
||||
let availability =
|
||||
real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_AVAILABILITY_CONDITION_ID)
|
||||
.expect("availability condition metadata should exist");
|
||||
assert_eq!(availability.label, "Unknown Loco Available");
|
||||
|
||||
let cost = real_ordinary_condition_metadata(REAL_NAMED_LOCOMOTIVE_COST_CONDITION_ID)
|
||||
.expect("cost condition metadata should exist");
|
||||
assert_eq!(cost.label, "Unknown Loco Cost");
|
||||
|
||||
let cargo = real_ordinary_condition_metadata(REAL_CARGO_PRODUCTION_TOTAL_CONDITION_ID)
|
||||
.expect("cargo condition metadata should exist");
|
||||
assert_eq!(cargo.label, "All Cargo Production");
|
||||
|
||||
let build_limit =
|
||||
real_ordinary_condition_metadata(REAL_LIMITED_TRACK_BUILDING_AMOUNT_CONDITION_ID)
|
||||
.expect("build-limit condition metadata should exist");
|
||||
assert_eq!(build_limit.label, "Limited Track Building Amount");
|
||||
|
||||
let access_cost = real_ordinary_condition_metadata(REAL_TERRITORY_ACCESS_COST_CONDITION_ID)
|
||||
.expect("territory-access-cost condition metadata should exist");
|
||||
assert_eq!(access_cost.label, "Access Rights Cost:");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn looks_up_checked_in_world_flag_descriptor_metadata() {
|
||||
let metadata =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue