Add territory and player packed event import
This commit is contained in:
parent
f73234cb99
commit
ca208f74e0
26 changed files with 1912 additions and 272 deletions
|
|
@ -174,6 +174,8 @@ mod tests {
|
|||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -339,6 +341,8 @@ mod tests {
|
|||
available_track_laying_capacity: None,
|
||||
}],
|
||||
selected_company_id: Some(42),
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ pub struct ExpectedRuntimeSummary {
|
|||
#[serde(default)]
|
||||
pub active_company_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub player_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub territory_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub company_territory_track_count: Option<usize>,
|
||||
|
|
@ -86,8 +88,16 @@ pub struct ExpectedRuntimeSummary {
|
|||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_company_role_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_player_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_player_selection_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_player_role_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_condition_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_missing_player_condition_context_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_company_condition_scope_disabled_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_player_condition_scope_count: Option<usize>,
|
||||
|
|
@ -104,6 +114,8 @@ pub struct ExpectedRuntimeSummary {
|
|||
#[serde(default)]
|
||||
pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_territory_policy_descriptor_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub packed_event_blocked_structural_only_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub event_runtime_record_count: Option<usize>,
|
||||
|
|
@ -353,6 +365,14 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.player_count {
|
||||
if actual.player_count != count {
|
||||
mismatches.push(format!(
|
||||
"player_count mismatch: expected {count}, got {}",
|
||||
actual.player_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.territory_count {
|
||||
if actual.territory_count != count {
|
||||
mismatches.push(format!(
|
||||
|
|
@ -441,6 +461,30 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_missing_player_context_count {
|
||||
if actual.packed_event_blocked_missing_player_context_count != count {
|
||||
mismatches.push(format!(
|
||||
"packed_event_blocked_missing_player_context_count mismatch: expected {count}, got {}",
|
||||
actual.packed_event_blocked_missing_player_context_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_missing_player_selection_context_count {
|
||||
if actual.packed_event_blocked_missing_player_selection_context_count != count {
|
||||
mismatches.push(format!(
|
||||
"packed_event_blocked_missing_player_selection_context_count mismatch: expected {count}, got {}",
|
||||
actual.packed_event_blocked_missing_player_selection_context_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_missing_player_role_context_count {
|
||||
if actual.packed_event_blocked_missing_player_role_context_count != count {
|
||||
mismatches.push(format!(
|
||||
"packed_event_blocked_missing_player_role_context_count mismatch: expected {count}, got {}",
|
||||
actual.packed_event_blocked_missing_player_role_context_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_missing_condition_context_count {
|
||||
if actual.packed_event_blocked_missing_condition_context_count != count {
|
||||
mismatches.push(format!(
|
||||
|
|
@ -449,6 +493,14 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_missing_player_condition_context_count {
|
||||
if actual.packed_event_blocked_missing_player_condition_context_count != count {
|
||||
mismatches.push(format!(
|
||||
"packed_event_blocked_missing_player_condition_context_count mismatch: expected {count}, got {}",
|
||||
actual.packed_event_blocked_missing_player_condition_context_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_company_condition_scope_disabled_count {
|
||||
if actual.packed_event_blocked_company_condition_scope_disabled_count != count {
|
||||
mismatches.push(format!(
|
||||
|
|
@ -513,6 +565,14 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_territory_policy_descriptor_count {
|
||||
if actual.packed_event_blocked_territory_policy_descriptor_count != count {
|
||||
mismatches.push(format!(
|
||||
"packed_event_blocked_territory_policy_descriptor_count mismatch: expected {count}, got {}",
|
||||
actual.packed_event_blocked_territory_policy_descriptor_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.packed_event_blocked_structural_only_count {
|
||||
if actual.packed_event_blocked_structural_only_count != count {
|
||||
mismatches.push(format!(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -41,9 +41,10 @@ pub use runtime::{
|
|||
RuntimeEventRecordTemplate, RuntimePackedEventCollectionSummary,
|
||||
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
|
||||
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
|
||||
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary,
|
||||
RuntimePlayerConditionTestScope, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState,
|
||||
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
|
||||
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
|
||||
RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric,
|
||||
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
RuntimeWorldRestoreState,
|
||||
};
|
||||
pub use smp::{
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ mod tests {
|
|||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ pub struct RuntimeTrackPieceCounts {
|
|||
pub struct RuntimeTerritory {
|
||||
pub territory_id: u32,
|
||||
#[serde(default)]
|
||||
pub name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub track_piece_counts: RuntimeTrackPieceCounts,
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +69,20 @@ pub struct RuntimeCompanyTerritoryTrackPieceCount {
|
|||
pub track_piece_counts: RuntimeTrackPieceCounts,
|
||||
}
|
||||
|
||||
fn runtime_player_default_active() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimePlayer {
|
||||
pub player_id: u32,
|
||||
pub current_cash: i64,
|
||||
#[serde(default = "runtime_player_default_active")]
|
||||
pub active: bool,
|
||||
#[serde(default)]
|
||||
pub controller_kind: RuntimeCompanyControllerKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum RuntimeCompanyTarget {
|
||||
|
|
@ -78,6 +94,24 @@ pub enum RuntimeCompanyTarget {
|
|||
Ids { ids: Vec<u32> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum RuntimePlayerTarget {
|
||||
AllActive,
|
||||
HumanPlayers,
|
||||
AiPlayers,
|
||||
SelectedPlayer,
|
||||
ConditionTruePlayer,
|
||||
Ids { ids: Vec<u32> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum RuntimeTerritoryTarget {
|
||||
AllTerritories,
|
||||
Ids { ids: Vec<u32> },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RuntimeCompanyConditionTestScope {
|
||||
|
|
@ -158,12 +192,14 @@ pub enum RuntimeCondition {
|
|||
value: i64,
|
||||
},
|
||||
TerritoryNumericThreshold {
|
||||
target: RuntimeTerritoryTarget,
|
||||
metric: RuntimeTerritoryMetric,
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
},
|
||||
CompanyTerritoryNumericThreshold {
|
||||
target: RuntimeCompanyTarget,
|
||||
territory: RuntimeTerritoryTarget,
|
||||
metric: RuntimeTrackMetric,
|
||||
comparator: RuntimeConditionComparator,
|
||||
value: i64,
|
||||
|
|
@ -181,6 +217,10 @@ pub enum RuntimeEffect {
|
|||
target: RuntimeCompanyTarget,
|
||||
value: i64,
|
||||
},
|
||||
SetPlayerCash {
|
||||
target: RuntimePlayerTarget,
|
||||
value: i64,
|
||||
},
|
||||
DeactivateCompany {
|
||||
target: RuntimeCompanyTarget,
|
||||
},
|
||||
|
|
@ -508,6 +548,10 @@ pub struct RuntimeState {
|
|||
#[serde(default)]
|
||||
pub selected_company_id: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub players: Vec<RuntimePlayer>,
|
||||
#[serde(default)]
|
||||
pub selected_player_id: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub territories: Vec<RuntimeTerritory>,
|
||||
#[serde(default)]
|
||||
pub company_territory_track_piece_counts: Vec<RuntimeCompanyTerritoryTrackPieceCount>,
|
||||
|
|
@ -552,11 +596,48 @@ impl RuntimeState {
|
|||
}
|
||||
}
|
||||
|
||||
let mut seen_player_ids = BTreeSet::new();
|
||||
let mut active_player_ids = BTreeSet::new();
|
||||
for player in &self.players {
|
||||
if !seen_player_ids.insert(player.player_id) {
|
||||
return Err(format!("duplicate player_id {}", player.player_id));
|
||||
}
|
||||
if player.active {
|
||||
active_player_ids.insert(player.player_id);
|
||||
}
|
||||
}
|
||||
if let Some(selected_player_id) = self.selected_player_id {
|
||||
if !seen_player_ids.contains(&selected_player_id) {
|
||||
return Err(format!(
|
||||
"selected_player_id {} does not reference a live player",
|
||||
selected_player_id
|
||||
));
|
||||
}
|
||||
if !active_player_ids.contains(&selected_player_id) {
|
||||
return Err(format!(
|
||||
"selected_player_id {} must reference an active player",
|
||||
selected_player_id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut seen_territory_ids = BTreeSet::new();
|
||||
let mut seen_territory_names = BTreeSet::new();
|
||||
for territory in &self.territories {
|
||||
if !seen_territory_ids.insert(territory.territory_id) {
|
||||
return Err(format!("duplicate territory_id {}", territory.territory_id));
|
||||
}
|
||||
if let Some(name) = territory.name.as_deref() {
|
||||
if name.trim().is_empty() {
|
||||
return Err(format!(
|
||||
"territory_id {} has an empty name",
|
||||
territory.territory_id
|
||||
));
|
||||
}
|
||||
if !seen_territory_names.insert(name.to_string()) {
|
||||
return Err(format!("duplicate territory name {name:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
for entry in &self.company_territory_track_piece_counts {
|
||||
if !seen_company_ids.contains(&entry.company_id) {
|
||||
|
|
@ -579,15 +660,22 @@ impl RuntimeState {
|
|||
return Err(format!("duplicate record_id {}", record.record_id));
|
||||
}
|
||||
for (condition_index, condition) in record.conditions.iter().enumerate() {
|
||||
validate_runtime_condition(condition, &seen_company_ids).map_err(|err| {
|
||||
validate_runtime_condition(condition, &seen_company_ids, &seen_territory_ids)
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"event_runtime_records[record_id={}].conditions[{condition_index}] {err}",
|
||||
record.record_id
|
||||
)
|
||||
})?;
|
||||
})?;
|
||||
}
|
||||
for (effect_index, effect) in record.effects.iter().enumerate() {
|
||||
validate_runtime_effect(effect, &seen_company_ids).map_err(|err| {
|
||||
validate_runtime_effect(
|
||||
effect,
|
||||
&seen_company_ids,
|
||||
&seen_player_ids,
|
||||
&seen_territory_ids,
|
||||
)
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"event_runtime_records[record_id={}].effects[{effect_index}] {err}",
|
||||
record.record_id
|
||||
|
|
@ -912,6 +1000,8 @@ impl RuntimeState {
|
|||
fn validate_runtime_effect(
|
||||
effect: &RuntimeEffect,
|
||||
valid_company_ids: &BTreeSet<u32>,
|
||||
valid_player_ids: &BTreeSet<u32>,
|
||||
valid_territory_ids: &BTreeSet<u32>,
|
||||
) -> Result<(), String> {
|
||||
match effect {
|
||||
RuntimeEffect::SetWorldFlag { key, .. } => {
|
||||
|
|
@ -926,6 +1016,9 @@ fn validate_runtime_effect(
|
|||
| RuntimeEffect::AdjustCompanyDebt { target, .. } => {
|
||||
validate_company_target(target, valid_company_ids)?;
|
||||
}
|
||||
RuntimeEffect::SetPlayerCash { target, .. } => {
|
||||
validate_player_target(target, valid_player_ids)?;
|
||||
}
|
||||
RuntimeEffect::SetCandidateAvailability { name, .. } => {
|
||||
if name.trim().is_empty() {
|
||||
return Err("name must not be empty".to_string());
|
||||
|
|
@ -937,7 +1030,12 @@ fn validate_runtime_effect(
|
|||
}
|
||||
}
|
||||
RuntimeEffect::AppendEventRecord { record } => {
|
||||
validate_event_record_template(record, valid_company_ids)?;
|
||||
validate_event_record_template(
|
||||
record,
|
||||
valid_company_ids,
|
||||
valid_player_ids,
|
||||
valid_territory_ids,
|
||||
)?;
|
||||
}
|
||||
RuntimeEffect::ActivateEventRecord { .. }
|
||||
| RuntimeEffect::DeactivateEventRecord { .. }
|
||||
|
|
@ -950,17 +1048,27 @@ fn validate_runtime_effect(
|
|||
fn validate_event_record_template(
|
||||
record: &RuntimeEventRecordTemplate,
|
||||
valid_company_ids: &BTreeSet<u32>,
|
||||
valid_player_ids: &BTreeSet<u32>,
|
||||
valid_territory_ids: &BTreeSet<u32>,
|
||||
) -> Result<(), String> {
|
||||
for (condition_index, condition) in record.conditions.iter().enumerate() {
|
||||
validate_runtime_condition(condition, valid_company_ids).map_err(|err| {
|
||||
validate_runtime_condition(condition, valid_company_ids, valid_territory_ids).map_err(
|
||||
|err| {
|
||||
format!(
|
||||
"template record_id={}.conditions[{condition_index}] {err}",
|
||||
record.record_id
|
||||
)
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
}
|
||||
for (effect_index, effect) in record.effects.iter().enumerate() {
|
||||
validate_runtime_effect(effect, valid_company_ids).map_err(|err| {
|
||||
validate_runtime_effect(
|
||||
effect,
|
||||
valid_company_ids,
|
||||
valid_player_ids,
|
||||
valid_territory_ids,
|
||||
)
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"template record_id={}.effects[{effect_index}] {err}",
|
||||
record.record_id
|
||||
|
|
@ -974,13 +1082,23 @@ fn validate_event_record_template(
|
|||
fn validate_runtime_condition(
|
||||
condition: &RuntimeCondition,
|
||||
valid_company_ids: &BTreeSet<u32>,
|
||||
valid_territory_ids: &BTreeSet<u32>,
|
||||
) -> Result<(), String> {
|
||||
match condition {
|
||||
RuntimeCondition::CompanyNumericThreshold { target, .. }
|
||||
| RuntimeCondition::CompanyTerritoryNumericThreshold { target, .. } => {
|
||||
RuntimeCondition::CompanyNumericThreshold { target, .. } => {
|
||||
validate_company_target(target, valid_company_ids)
|
||||
}
|
||||
RuntimeCondition::TerritoryNumericThreshold { .. } => Ok(()),
|
||||
RuntimeCondition::TerritoryNumericThreshold { target, .. } => {
|
||||
validate_territory_target(target, valid_territory_ids)
|
||||
}
|
||||
RuntimeCondition::CompanyTerritoryNumericThreshold {
|
||||
target,
|
||||
territory,
|
||||
..
|
||||
} => {
|
||||
validate_company_target(target, valid_company_ids)?;
|
||||
validate_territory_target(territory, valid_territory_ids)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1008,6 +1126,52 @@ fn validate_company_target(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_player_target(
|
||||
target: &RuntimePlayerTarget,
|
||||
valid_player_ids: &BTreeSet<u32>,
|
||||
) -> Result<(), String> {
|
||||
match target {
|
||||
RuntimePlayerTarget::AllActive
|
||||
| RuntimePlayerTarget::HumanPlayers
|
||||
| RuntimePlayerTarget::AiPlayers
|
||||
| RuntimePlayerTarget::SelectedPlayer
|
||||
| RuntimePlayerTarget::ConditionTruePlayer => Ok(()),
|
||||
RuntimePlayerTarget::Ids { ids } => {
|
||||
if ids.is_empty() {
|
||||
return Err("target ids must not be empty".to_string());
|
||||
}
|
||||
for player_id in ids {
|
||||
if !valid_player_ids.contains(player_id) {
|
||||
return Err(format!("target references unknown player_id {player_id}"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_territory_target(
|
||||
target: &RuntimeTerritoryTarget,
|
||||
valid_territory_ids: &BTreeSet<u32>,
|
||||
) -> Result<(), String> {
|
||||
match target {
|
||||
RuntimeTerritoryTarget::AllTerritories => Ok(()),
|
||||
RuntimeTerritoryTarget::Ids { ids } => {
|
||||
if ids.is_empty() {
|
||||
return Err("territory target ids must not be empty".to_string());
|
||||
}
|
||||
for territory_id in ids {
|
||||
if !valid_territory_ids.contains(territory_id) {
|
||||
return Err(format!(
|
||||
"territory target references unknown territory_id {territory_id}"
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -1050,6 +1214,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -1099,6 +1265,8 @@ mod tests {
|
|||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -1136,6 +1304,8 @@ mod tests {
|
|||
controller_kind: RuntimeCompanyControllerKind::Unknown,
|
||||
}],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -1186,6 +1356,8 @@ mod tests {
|
|||
controller_kind: RuntimeCompanyControllerKind::Unknown,
|
||||
}],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -1236,6 +1408,8 @@ mod tests {
|
|||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: Some(RuntimePackedEventCollectionSummary {
|
||||
|
|
@ -1337,6 +1511,8 @@ mod tests {
|
|||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
}],
|
||||
selected_company_id: Some(2),
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
@ -1374,6 +1550,8 @@ mod tests {
|
|||
controller_kind: RuntimeCompanyControllerKind::Human,
|
||||
}],
|
||||
selected_company_id: Some(1),
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use sha2::{Digest, Sha256};
|
|||
use crate::{
|
||||
RuntimeCompanyConditionTestScope, RuntimeCompanyMetric, RuntimeCompanyTarget,
|
||||
RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
|
||||
RuntimePlayerConditionTestScope, RuntimeTerritoryMetric, RuntimeTrackMetric,
|
||||
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeTerritoryMetric,
|
||||
RuntimeTerritoryTarget, RuntimeTrackMetric,
|
||||
};
|
||||
|
||||
pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec;
|
||||
|
|
@ -132,7 +133,7 @@ const REAL_GROUPED_EFFECT_DESCRIPTOR_METADATA: [RealGroupedEffectDescriptorMetad
|
|||
label: "Player Cash",
|
||||
target_mask_bits: 0x02,
|
||||
parameter_family: "player_finance_scalar",
|
||||
executable_in_runtime: false,
|
||||
executable_in_runtime: true,
|
||||
},
|
||||
RealGroupedEffectDescriptorMetadata {
|
||||
descriptor_id: 2,
|
||||
|
|
@ -2471,6 +2472,7 @@ fn decode_real_condition_row(
|
|||
negative_sentinel_scope
|
||||
.filter(|scope| scope.territory_scope_selector_is_0x63)
|
||||
.map(|_| RuntimeCondition::TerritoryNumericThreshold {
|
||||
target: RuntimeTerritoryTarget::AllTerritories,
|
||||
metric,
|
||||
comparator,
|
||||
value,
|
||||
|
|
@ -2481,6 +2483,7 @@ fn decode_real_condition_row(
|
|||
.filter(|scope| scope.territory_scope_selector_is_0x63)
|
||||
.map(|_| RuntimeCondition::CompanyTerritoryNumericThreshold {
|
||||
target: RuntimeCompanyTarget::ConditionTrueCompany,
|
||||
territory: RuntimeTerritoryTarget::AllTerritories,
|
||||
metric,
|
||||
comparator,
|
||||
value,
|
||||
|
|
@ -2588,19 +2591,25 @@ fn decode_real_grouped_effect_action(
|
|||
.grouped_target_scope_ordinals_0x7fb
|
||||
.get(row.group_index)
|
||||
.copied()?;
|
||||
let target = match target_scope_ordinal {
|
||||
0 => RuntimeCompanyTarget::ConditionTrueCompany,
|
||||
1 => RuntimeCompanyTarget::SelectedCompany,
|
||||
2 => RuntimeCompanyTarget::HumanCompanies,
|
||||
3 => RuntimeCompanyTarget::AiCompanies,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if descriptor_metadata.executable_in_runtime
|
||||
&& descriptor_metadata.descriptor_id == 1
|
||||
&& row.opcode == 8
|
||||
&& row.row_shape == "multivalue_scalar"
|
||||
{
|
||||
let target = real_grouped_player_target(target_scope_ordinal)?;
|
||||
return Some(RuntimeEffect::SetPlayerCash {
|
||||
target,
|
||||
value: i64::from(row.raw_scalar_value),
|
||||
});
|
||||
}
|
||||
|
||||
if descriptor_metadata.executable_in_runtime
|
||||
&& descriptor_metadata.descriptor_id == 2
|
||||
&& row.opcode == 8
|
||||
&& row.row_shape == "multivalue_scalar"
|
||||
{
|
||||
let target = real_grouped_company_target(target_scope_ordinal)?;
|
||||
return Some(RuntimeEffect::SetCompanyCash {
|
||||
target,
|
||||
value: i64::from(row.raw_scalar_value),
|
||||
|
|
@ -2612,6 +2621,7 @@ fn decode_real_grouped_effect_action(
|
|||
&& row.row_shape == "bool_toggle"
|
||||
&& row.raw_scalar_value != 0
|
||||
{
|
||||
let target = real_grouped_company_target(target_scope_ordinal)?;
|
||||
return Some(RuntimeEffect::DeactivateCompany { target });
|
||||
}
|
||||
|
||||
|
|
@ -2620,6 +2630,7 @@ fn decode_real_grouped_effect_action(
|
|||
&& row.row_shape == "scalar_assignment"
|
||||
&& row.raw_scalar_value >= 0
|
||||
{
|
||||
let target = real_grouped_company_target(target_scope_ordinal)?;
|
||||
return Some(RuntimeEffect::SetCompanyTrackLayingCapacity {
|
||||
target,
|
||||
value: Some(row.raw_scalar_value as u32),
|
||||
|
|
@ -2629,6 +2640,26 @@ fn decode_real_grouped_effect_action(
|
|||
None
|
||||
}
|
||||
|
||||
fn real_grouped_company_target(ordinal: u8) -> Option<RuntimeCompanyTarget> {
|
||||
match ordinal {
|
||||
0 => Some(RuntimeCompanyTarget::ConditionTrueCompany),
|
||||
1 => Some(RuntimeCompanyTarget::SelectedCompany),
|
||||
2 => Some(RuntimeCompanyTarget::HumanCompanies),
|
||||
3 => Some(RuntimeCompanyTarget::AiCompanies),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn real_grouped_player_target(ordinal: u8) -> Option<RuntimePlayerTarget> {
|
||||
match ordinal {
|
||||
0 => Some(RuntimePlayerTarget::ConditionTruePlayer),
|
||||
1 => Some(RuntimePlayerTarget::SelectedPlayer),
|
||||
2 => Some(RuntimePlayerTarget::HumanPlayers),
|
||||
3 => Some(RuntimePlayerTarget::AiPlayers),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_synthetic_packed_event_action(bytes: &[u8], cursor: &mut usize) -> Option<RuntimeEffect> {
|
||||
let opcode = read_u8_at(bytes, *cursor)?;
|
||||
*cursor += 1;
|
||||
|
|
@ -2784,6 +2815,15 @@ fn runtime_effect_supported_for_save_import(effect: &RuntimeEffect) -> bool {
|
|||
| RuntimeEffect::ActivateEventRecord { .. }
|
||||
| RuntimeEffect::DeactivateEventRecord { .. }
|
||||
| RuntimeEffect::RemoveEventRecord { .. } => true,
|
||||
RuntimeEffect::SetPlayerCash { target, .. } => matches!(
|
||||
target,
|
||||
RuntimePlayerTarget::AllActive
|
||||
| RuntimePlayerTarget::Ids { .. }
|
||||
| RuntimePlayerTarget::HumanPlayers
|
||||
| RuntimePlayerTarget::AiPlayers
|
||||
| RuntimePlayerTarget::SelectedPlayer
|
||||
| RuntimePlayerTarget::ConditionTruePlayer
|
||||
),
|
||||
RuntimeEffect::SetCompanyCash { target, .. }
|
||||
| RuntimeEffect::AdjustCompanyCash { target, .. }
|
||||
| RuntimeEffect::AdjustCompanyDebt { target, .. } => matches!(
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
|
||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate, RuntimeState,
|
||||
RuntimeSummary, RuntimeTerritoryMetric, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate, RuntimePlayerTarget,
|
||||
RuntimeState, RuntimeSummary, RuntimeTerritoryMetric, RuntimeTerritoryTarget,
|
||||
RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
calendar::BoundaryEventKind,
|
||||
};
|
||||
|
||||
|
|
@ -48,6 +49,7 @@ pub struct ServiceEvent {
|
|||
pub serviced_record_ids: Vec<u32>,
|
||||
pub applied_effect_count: u32,
|
||||
pub mutated_company_ids: Vec<u32>,
|
||||
pub mutated_player_ids: Vec<u32>,
|
||||
pub appended_record_ids: Vec<u32>,
|
||||
pub activated_record_ids: Vec<u32>,
|
||||
pub deactivated_record_ids: Vec<u32>,
|
||||
|
|
@ -84,6 +86,7 @@ struct AppliedEffectsSummary {
|
|||
#[derive(Debug, Default)]
|
||||
struct ResolvedConditionContext {
|
||||
matching_company_ids: BTreeSet<u32>,
|
||||
matching_player_ids: BTreeSet<u32>,
|
||||
}
|
||||
|
||||
pub fn execute_step_command(
|
||||
|
|
@ -205,6 +208,7 @@ fn service_trigger_kind(
|
|||
let mut serviced_record_ids = Vec::new();
|
||||
let mut applied_effect_count = 0_u32;
|
||||
let mut mutated_company_ids = BTreeSet::new();
|
||||
let mut mutated_player_ids = BTreeSet::new();
|
||||
let mut appended_record_ids = Vec::new();
|
||||
let mut activated_record_ids = Vec::new();
|
||||
let mut deactivated_record_ids = Vec::new();
|
||||
|
|
@ -245,6 +249,7 @@ fn service_trigger_kind(
|
|||
&record_effects,
|
||||
&condition_context,
|
||||
&mut mutated_company_ids,
|
||||
&mut mutated_player_ids,
|
||||
&mut staged_event_graph_mutations,
|
||||
)?;
|
||||
applied_effect_count += effect_summary.applied_effect_count;
|
||||
|
|
@ -276,6 +281,7 @@ fn service_trigger_kind(
|
|||
serviced_record_ids,
|
||||
applied_effect_count,
|
||||
mutated_company_ids: mutated_company_ids.into_iter().collect(),
|
||||
mutated_player_ids: mutated_player_ids.into_iter().collect(),
|
||||
appended_record_ids,
|
||||
activated_record_ids,
|
||||
deactivated_record_ids,
|
||||
|
|
@ -296,6 +302,7 @@ fn apply_runtime_effects(
|
|||
effects: &[RuntimeEffect],
|
||||
condition_context: &ResolvedConditionContext,
|
||||
mutated_company_ids: &mut BTreeSet<u32>,
|
||||
mutated_player_ids: &mut BTreeSet<u32>,
|
||||
staged_event_graph_mutations: &mut Vec<EventGraphMutation>,
|
||||
) -> Result<AppliedEffectsSummary, String> {
|
||||
let mut summary = AppliedEffectsSummary::default();
|
||||
|
|
@ -319,6 +326,20 @@ fn apply_runtime_effects(
|
|||
mutated_company_ids.insert(company_id);
|
||||
}
|
||||
}
|
||||
RuntimeEffect::SetPlayerCash { target, value } => {
|
||||
let player_ids = resolve_player_target_ids(state, target, condition_context)?;
|
||||
for player_id in player_ids {
|
||||
let player = state
|
||||
.players
|
||||
.iter_mut()
|
||||
.find(|player| player.player_id == player_id)
|
||||
.ok_or_else(|| {
|
||||
format!("missing player_id {player_id} while applying cash effect")
|
||||
})?;
|
||||
player.current_cash = *value;
|
||||
mutated_player_ids.insert(player_id);
|
||||
}
|
||||
}
|
||||
RuntimeEffect::DeactivateCompany { target } => {
|
||||
let company_ids = resolve_company_target_ids(state, target, condition_context)?;
|
||||
for company_id in company_ids {
|
||||
|
|
@ -520,21 +541,25 @@ fn evaluate_record_conditions(
|
|||
}
|
||||
}
|
||||
RuntimeCondition::TerritoryNumericThreshold {
|
||||
target,
|
||||
metric,
|
||||
comparator,
|
||||
value,
|
||||
} => {
|
||||
let actual = territory_metric_value(state, *metric);
|
||||
let territory_ids = resolve_territory_target_ids(state, target)?;
|
||||
let actual = territory_metric_value(state, &territory_ids, *metric);
|
||||
if !compare_condition_value(actual, *comparator, *value) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
RuntimeCondition::CompanyTerritoryNumericThreshold {
|
||||
target,
|
||||
territory,
|
||||
metric,
|
||||
comparator,
|
||||
value,
|
||||
} => {
|
||||
let territory_ids = resolve_territory_target_ids(state, territory)?;
|
||||
let resolved = resolve_company_target_ids(
|
||||
state,
|
||||
target,
|
||||
|
|
@ -544,7 +569,12 @@ fn evaluate_record_conditions(
|
|||
.into_iter()
|
||||
.filter(|company_id| {
|
||||
compare_condition_value(
|
||||
company_territory_metric_value(state, *company_id, *metric),
|
||||
company_territory_metric_value(
|
||||
state,
|
||||
*company_id,
|
||||
&territory_ids,
|
||||
*metric,
|
||||
),
|
||||
*comparator,
|
||||
*value,
|
||||
)
|
||||
|
|
@ -563,6 +593,7 @@ fn evaluate_record_conditions(
|
|||
|
||||
Ok(Some(ResolvedConditionContext {
|
||||
matching_company_ids: company_matches.unwrap_or_default(),
|
||||
matching_player_ids: BTreeSet::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -676,6 +707,119 @@ fn resolve_company_target_ids(
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_player_target_ids(
|
||||
state: &RuntimeState,
|
||||
target: &RuntimePlayerTarget,
|
||||
condition_context: &ResolvedConditionContext,
|
||||
) -> Result<Vec<u32>, String> {
|
||||
match target {
|
||||
RuntimePlayerTarget::AllActive => Ok(state
|
||||
.players
|
||||
.iter()
|
||||
.filter(|player| player.active)
|
||||
.map(|player| player.player_id)
|
||||
.collect()),
|
||||
RuntimePlayerTarget::Ids { ids } => {
|
||||
let known_ids = state
|
||||
.players
|
||||
.iter()
|
||||
.map(|player| player.player_id)
|
||||
.collect::<BTreeSet<_>>();
|
||||
for player_id in ids {
|
||||
if !known_ids.contains(player_id) {
|
||||
return Err(format!("target references unknown player_id {player_id}"));
|
||||
}
|
||||
}
|
||||
Ok(ids.clone())
|
||||
}
|
||||
RuntimePlayerTarget::HumanPlayers => {
|
||||
if state
|
||||
.players
|
||||
.iter()
|
||||
.any(|player| player.controller_kind == RuntimeCompanyControllerKind::Unknown)
|
||||
{
|
||||
return Err(
|
||||
"target requires player role context but at least one player has unknown controller_kind"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
Ok(state
|
||||
.players
|
||||
.iter()
|
||||
.filter(|player| {
|
||||
player.active && player.controller_kind == RuntimeCompanyControllerKind::Human
|
||||
})
|
||||
.map(|player| player.player_id)
|
||||
.collect())
|
||||
}
|
||||
RuntimePlayerTarget::AiPlayers => {
|
||||
if state
|
||||
.players
|
||||
.iter()
|
||||
.any(|player| player.controller_kind == RuntimeCompanyControllerKind::Unknown)
|
||||
{
|
||||
return Err(
|
||||
"target requires player role context but at least one player has unknown controller_kind"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
Ok(state
|
||||
.players
|
||||
.iter()
|
||||
.filter(|player| {
|
||||
player.active && player.controller_kind == RuntimeCompanyControllerKind::Ai
|
||||
})
|
||||
.map(|player| player.player_id)
|
||||
.collect())
|
||||
}
|
||||
RuntimePlayerTarget::SelectedPlayer => {
|
||||
let selected_player_id = state
|
||||
.selected_player_id
|
||||
.ok_or_else(|| "target requires selected_player_id context".to_string())?;
|
||||
if state
|
||||
.players
|
||||
.iter()
|
||||
.any(|player| player.player_id == selected_player_id && player.active)
|
||||
{
|
||||
Ok(vec![selected_player_id])
|
||||
} else {
|
||||
Err("target requires selected_player_id to reference an active player".to_string())
|
||||
}
|
||||
}
|
||||
RuntimePlayerTarget::ConditionTruePlayer => {
|
||||
if condition_context.matching_player_ids.is_empty() {
|
||||
Err("target requires player condition-evaluation context".to_string())
|
||||
} else {
|
||||
Ok(condition_context.matching_player_ids.iter().copied().collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_territory_target_ids(
|
||||
state: &RuntimeState,
|
||||
target: &RuntimeTerritoryTarget,
|
||||
) -> Result<Vec<u32>, String> {
|
||||
match target {
|
||||
RuntimeTerritoryTarget::AllTerritories => {
|
||||
Ok(state.territories.iter().map(|territory| territory.territory_id).collect())
|
||||
}
|
||||
RuntimeTerritoryTarget::Ids { ids } => {
|
||||
let known_ids = state
|
||||
.territories
|
||||
.iter()
|
||||
.map(|territory| territory.territory_id)
|
||||
.collect::<BTreeSet<_>>();
|
||||
for territory_id in ids {
|
||||
if !known_ids.contains(territory_id) {
|
||||
return Err(format!("territory target references unknown territory_id {territory_id}"));
|
||||
}
|
||||
}
|
||||
Ok(ids.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn company_metric_value(company: &crate::RuntimeCompany, metric: RuntimeCompanyMetric) -> i64 {
|
||||
match metric {
|
||||
RuntimeCompanyMetric::CurrentCash => company.current_cash,
|
||||
|
|
@ -697,9 +841,14 @@ fn company_metric_value(company: &crate::RuntimeCompany, metric: RuntimeCompanyM
|
|||
}
|
||||
}
|
||||
|
||||
fn territory_metric_value(state: &RuntimeState, metric: RuntimeTerritoryMetric) -> i64 {
|
||||
fn territory_metric_value(
|
||||
state: &RuntimeState,
|
||||
territory_ids: &[u32],
|
||||
metric: RuntimeTerritoryMetric,
|
||||
) -> i64 {
|
||||
state.territories
|
||||
.iter()
|
||||
.filter(|territory| territory_ids.contains(&territory.territory_id))
|
||||
.map(|territory| {
|
||||
track_piece_metric_value(
|
||||
territory.track_piece_counts,
|
||||
|
|
@ -712,11 +861,12 @@ fn territory_metric_value(state: &RuntimeState, metric: RuntimeTerritoryMetric)
|
|||
fn company_territory_metric_value(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
territory_ids: &[u32],
|
||||
metric: RuntimeTrackMetric,
|
||||
) -> i64 {
|
||||
state.company_territory_track_piece_counts
|
||||
.iter()
|
||||
.filter(|entry| entry.company_id == company_id)
|
||||
.filter(|entry| entry.company_id == company_id && territory_ids.contains(&entry.territory_id))
|
||||
.map(|entry| track_piece_metric_value(entry.track_piece_counts, metric))
|
||||
.sum()
|
||||
}
|
||||
|
|
@ -805,6 +955,8 @@ mod tests {
|
|||
available_track_laying_capacity: None,
|
||||
}],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ pub struct RuntimeSummary {
|
|||
pub metadata_count: usize,
|
||||
pub company_count: usize,
|
||||
pub active_company_count: usize,
|
||||
pub player_count: usize,
|
||||
pub territory_count: usize,
|
||||
pub company_territory_track_count: usize,
|
||||
pub packed_event_collection_present: bool,
|
||||
|
|
@ -40,7 +41,11 @@ pub struct RuntimeSummary {
|
|||
pub packed_event_blocked_missing_company_context_count: usize,
|
||||
pub packed_event_blocked_missing_selection_context_count: usize,
|
||||
pub packed_event_blocked_missing_company_role_context_count: usize,
|
||||
pub packed_event_blocked_missing_player_context_count: usize,
|
||||
pub packed_event_blocked_missing_player_selection_context_count: usize,
|
||||
pub packed_event_blocked_missing_player_role_context_count: usize,
|
||||
pub packed_event_blocked_missing_condition_context_count: usize,
|
||||
pub packed_event_blocked_missing_player_condition_context_count: usize,
|
||||
pub packed_event_blocked_company_condition_scope_disabled_count: usize,
|
||||
pub packed_event_blocked_player_condition_scope_count: usize,
|
||||
pub packed_event_blocked_territory_condition_scope_count: usize,
|
||||
|
|
@ -49,6 +54,7 @@ pub struct RuntimeSummary {
|
|||
pub packed_event_blocked_unmapped_ordinary_condition_count: usize,
|
||||
pub packed_event_blocked_missing_compact_control_count: usize,
|
||||
pub packed_event_blocked_unmapped_real_descriptor_count: usize,
|
||||
pub packed_event_blocked_territory_policy_descriptor_count: usize,
|
||||
pub packed_event_blocked_structural_only_count: usize,
|
||||
pub event_runtime_record_count: usize,
|
||||
pub candidate_availability_count: usize,
|
||||
|
|
@ -136,6 +142,7 @@ impl RuntimeSummary {
|
|||
.iter()
|
||||
.filter(|company| company.active)
|
||||
.count(),
|
||||
player_count: state.players.len(),
|
||||
territory_count: state.territories.len(),
|
||||
company_territory_track_count: state.company_territory_track_piece_counts.len(),
|
||||
packed_event_collection_present: state.packed_event_collection.is_some(),
|
||||
|
|
@ -218,6 +225,48 @@ impl RuntimeSummary {
|
|||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_missing_player_context_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.filter(|record| {
|
||||
record.import_outcome.as_deref()
|
||||
== Some("blocked_missing_player_context")
|
||||
})
|
||||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_missing_player_selection_context_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.filter(|record| {
|
||||
record.import_outcome.as_deref()
|
||||
== Some("blocked_missing_player_selection_context")
|
||||
})
|
||||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_missing_player_role_context_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.filter(|record| {
|
||||
record.import_outcome.as_deref()
|
||||
== Some("blocked_missing_player_role_context")
|
||||
})
|
||||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_missing_condition_context_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
|
|
@ -232,6 +281,20 @@ impl RuntimeSummary {
|
|||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_missing_player_condition_context_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.filter(|record| {
|
||||
record.import_outcome.as_deref()
|
||||
== Some("blocked_missing_player_condition_context")
|
||||
})
|
||||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_company_condition_scope_disabled_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
|
|
@ -344,6 +407,20 @@ impl RuntimeSummary {
|
|||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_territory_policy_descriptor_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
.map(|summary| {
|
||||
summary
|
||||
.records
|
||||
.iter()
|
||||
.filter(|record| {
|
||||
record.import_outcome.as_deref()
|
||||
== Some("blocked_territory_policy_descriptor")
|
||||
})
|
||||
.count()
|
||||
})
|
||||
.unwrap_or(0),
|
||||
packed_event_blocked_structural_only_count: state
|
||||
.packed_event_collection
|
||||
.as_ref()
|
||||
|
|
@ -425,6 +502,8 @@ mod tests {
|
|||
metadata: BTreeMap::new(),
|
||||
companies: Vec::new(),
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: Some(RuntimePackedEventCollectionSummary {
|
||||
|
|
@ -650,6 +729,8 @@ mod tests {
|
|||
},
|
||||
],
|
||||
selected_company_id: None,
|
||||
players: Vec::new(),
|
||||
selected_player_id: None,
|
||||
territories: Vec::new(),
|
||||
company_territory_track_piece_counts: Vec::new(),
|
||||
packed_event_collection: None,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue