Refresh company periodic side latches at boundary
This commit is contained in:
parent
b1c6dad723
commit
6fc8da2153
3 changed files with 215 additions and 13 deletions
|
|
@ -2395,13 +2395,14 @@ impl RuntimeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let known_company_ids = self
|
||||||
|
.companies
|
||||||
|
.iter()
|
||||||
|
.map(|company| company.company_id)
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
self.service_state
|
self.service_state
|
||||||
.company_periodic_side_latch_state
|
.company_periodic_side_latch_state
|
||||||
.retain(|company_id, _| {
|
.retain(|company_id, _| known_company_ids.contains(company_id));
|
||||||
self.service_state
|
|
||||||
.company_market_state
|
|
||||||
.contains_key(company_id)
|
|
||||||
});
|
|
||||||
for (company_id, market_state) in &self.service_state.company_market_state {
|
for (company_id, market_state) in &self.service_state.company_market_state {
|
||||||
self.service_state
|
self.service_state
|
||||||
.company_periodic_side_latch_state
|
.company_periodic_side_latch_state
|
||||||
|
|
@ -6818,6 +6819,93 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preserves_company_periodic_side_latch_state_without_market_projection() {
|
||||||
|
let mut state = RuntimeState {
|
||||||
|
calendar: CalendarPoint {
|
||||||
|
year: 1830,
|
||||||
|
month_slot: 0,
|
||||||
|
phase_slot: 0,
|
||||||
|
tick_slot: 0,
|
||||||
|
},
|
||||||
|
world_flags: BTreeMap::new(),
|
||||||
|
save_profile: RuntimeSaveProfileState::default(),
|
||||||
|
world_restore: RuntimeWorldRestoreState::default(),
|
||||||
|
metadata: BTreeMap::new(),
|
||||||
|
companies: vec![RuntimeCompany {
|
||||||
|
company_id: 1,
|
||||||
|
current_cash: 0,
|
||||||
|
debt: 0,
|
||||||
|
credit_rating_score: None,
|
||||||
|
prime_rate: None,
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
active: true,
|
||||||
|
available_track_laying_capacity: None,
|
||||||
|
linked_chairman_profile_id: None,
|
||||||
|
book_value_per_share: 0,
|
||||||
|
investor_confidence: 0,
|
||||||
|
management_attitude: 0,
|
||||||
|
takeover_cooldown_year: None,
|
||||||
|
merger_cooldown_year: None,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Unknown,
|
||||||
|
}],
|
||||||
|
selected_company_id: Some(1),
|
||||||
|
players: Vec::new(),
|
||||||
|
selected_player_id: None,
|
||||||
|
chairman_profiles: Vec::new(),
|
||||||
|
selected_chairman_profile_id: None,
|
||||||
|
trains: Vec::new(),
|
||||||
|
locomotive_catalog: Vec::new(),
|
||||||
|
cargo_catalog: Vec::new(),
|
||||||
|
territories: Vec::new(),
|
||||||
|
company_territory_track_piece_counts: Vec::new(),
|
||||||
|
company_territory_access: Vec::new(),
|
||||||
|
packed_event_collection: None,
|
||||||
|
event_runtime_records: Vec::new(),
|
||||||
|
candidate_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_availability: BTreeMap::new(),
|
||||||
|
named_locomotive_cost: BTreeMap::new(),
|
||||||
|
all_cargo_price_override: None,
|
||||||
|
named_cargo_price_overrides: BTreeMap::new(),
|
||||||
|
all_cargo_production_override: None,
|
||||||
|
factory_cargo_production_override: None,
|
||||||
|
farm_mine_cargo_production_override: None,
|
||||||
|
named_cargo_production_overrides: BTreeMap::new(),
|
||||||
|
cargo_production_overrides: BTreeMap::new(),
|
||||||
|
world_runtime_variables: BTreeMap::new(),
|
||||||
|
company_runtime_variables: BTreeMap::new(),
|
||||||
|
player_runtime_variables: BTreeMap::new(),
|
||||||
|
territory_runtime_variables: BTreeMap::new(),
|
||||||
|
world_scalar_overrides: BTreeMap::new(),
|
||||||
|
special_conditions: BTreeMap::new(),
|
||||||
|
service_state: RuntimeServiceState {
|
||||||
|
company_periodic_side_latch_state: BTreeMap::from([(
|
||||||
|
1,
|
||||||
|
RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: Some(2),
|
||||||
|
city_connection_latch: true,
|
||||||
|
linked_transit_latch: false,
|
||||||
|
},
|
||||||
|
)]),
|
||||||
|
..RuntimeServiceState::default()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
state.refresh_derived_market_state();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.get(&1),
|
||||||
|
Some(&RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: Some(2),
|
||||||
|
city_connection_latch: true,
|
||||||
|
linked_transit_latch: false,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reads_grounded_company_stat_family_slots_from_runtime_state() {
|
fn reads_grounded_company_stat_family_slots_from_runtime_state() {
|
||||||
let mut year_stat_family_qword_bits = vec![
|
let mut year_stat_family_qword_bits = vec![
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,7 @@ fn service_periodic_boundary(
|
||||||
service_events: &mut Vec<ServiceEvent>,
|
service_events: &mut Vec<ServiceEvent>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
state.service_state.periodic_boundary_calls += 1;
|
state.service_state.periodic_boundary_calls += 1;
|
||||||
|
service_refresh_company_periodic_side_latch_state(state);
|
||||||
|
|
||||||
for trigger_kind in PERIODIC_TRIGGER_KIND_ORDER {
|
for trigger_kind in PERIODIC_TRIGGER_KIND_ORDER {
|
||||||
service_trigger_kind(state, trigger_kind, service_events)?;
|
service_trigger_kind(state, trigger_kind, service_events)?;
|
||||||
|
|
@ -256,6 +257,52 @@ fn service_periodic_boundary(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn service_refresh_company_periodic_side_latch_state(state: &mut RuntimeState) {
|
||||||
|
let active_company_ids = state
|
||||||
|
.companies
|
||||||
|
.iter()
|
||||||
|
.filter(|company| company.active)
|
||||||
|
.map(|company| company.company_id)
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.retain(|company_id, _| active_company_ids.contains(company_id));
|
||||||
|
|
||||||
|
for company_id in active_company_ids {
|
||||||
|
match (
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.get_mut(&company_id),
|
||||||
|
state.service_state.company_market_state.get(&company_id),
|
||||||
|
) {
|
||||||
|
(Some(latch_state), Some(market_state)) => {
|
||||||
|
latch_state.preferred_locomotive_engine_type_raw_u8 = None;
|
||||||
|
latch_state.city_connection_latch = market_state.city_connection_latch;
|
||||||
|
latch_state.linked_transit_latch = market_state.linked_transit_latch;
|
||||||
|
}
|
||||||
|
(Some(latch_state), None) => {
|
||||||
|
latch_state.preferred_locomotive_engine_type_raw_u8 = None;
|
||||||
|
}
|
||||||
|
(None, Some(market_state)) => {
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.insert(
|
||||||
|
company_id,
|
||||||
|
crate::RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: None,
|
||||||
|
city_connection_latch: market_state.city_connection_latch,
|
||||||
|
linked_transit_latch: market_state.linked_transit_latch,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(None, None) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn service_decode_saved_f64_bits(raw_bits: u64) -> Option<f64> {
|
fn service_decode_saved_f64_bits(raw_bits: u64) -> Option<f64> {
|
||||||
let value = f64::from_bits(raw_bits);
|
let value = f64::from_bits(raw_bits);
|
||||||
value.is_finite().then_some(value)
|
value.is_finite().then_some(value)
|
||||||
|
|
@ -2884,11 +2931,11 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
CalendarPoint, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
|
CalendarPoint, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
|
||||||
RuntimeChairmanMetric, RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
RuntimeChairmanMetric, RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
||||||
RuntimeCompanyControllerKind, RuntimeCompanyTarget, RuntimeCondition,
|
RuntimeCompanyControllerKind, RuntimeCompanyPeriodicSideLatchState, RuntimeCompanyTarget,
|
||||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
|
RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord,
|
||||||
RuntimePlayer, RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState,
|
RuntimeEventRecordTemplate, RuntimePlayer, RuntimePlayerTarget, RuntimeSaveProfileState,
|
||||||
RuntimeTerritory, RuntimeTerritoryTarget, RuntimeTrackPieceCounts, RuntimeTrain,
|
RuntimeServiceState, RuntimeTerritory, RuntimeTerritoryTarget, RuntimeTrackPieceCounts,
|
||||||
RuntimeWorldRestoreState,
|
RuntimeTrain, RuntimeWorldRestoreState,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn state() -> RuntimeState {
|
fn state() -> RuntimeState {
|
||||||
|
|
@ -3227,6 +3274,70 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn periodic_boundary_clears_transient_preferred_locomotive_side_latch() {
|
||||||
|
let mut state = state();
|
||||||
|
state.service_state.company_periodic_side_latch_state = BTreeMap::from([(
|
||||||
|
1,
|
||||||
|
RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: Some(2),
|
||||||
|
city_connection_latch: true,
|
||||||
|
linked_transit_latch: false,
|
||||||
|
},
|
||||||
|
)]);
|
||||||
|
|
||||||
|
execute_step_command(&mut state, &StepCommand::ServicePeriodicBoundary)
|
||||||
|
.expect("periodic boundary should refresh periodic side latches");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.get(&1),
|
||||||
|
Some(&RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: None,
|
||||||
|
city_connection_latch: true,
|
||||||
|
linked_transit_latch: false,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn periodic_boundary_reseeds_finance_side_latches_from_market_state() {
|
||||||
|
let mut state = state();
|
||||||
|
state.service_state.company_market_state = BTreeMap::from([(
|
||||||
|
1,
|
||||||
|
crate::RuntimeCompanyMarketState {
|
||||||
|
city_connection_latch: false,
|
||||||
|
linked_transit_latch: true,
|
||||||
|
..crate::RuntimeCompanyMarketState::default()
|
||||||
|
},
|
||||||
|
)]);
|
||||||
|
state.service_state.company_periodic_side_latch_state = BTreeMap::from([(
|
||||||
|
1,
|
||||||
|
RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: Some(2),
|
||||||
|
city_connection_latch: true,
|
||||||
|
linked_transit_latch: false,
|
||||||
|
},
|
||||||
|
)]);
|
||||||
|
|
||||||
|
execute_step_command(&mut state, &StepCommand::ServicePeriodicBoundary)
|
||||||
|
.expect("periodic boundary should reseed finance latches from market state");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state
|
||||||
|
.service_state
|
||||||
|
.company_periodic_side_latch_state
|
||||||
|
.get(&1),
|
||||||
|
Some(&RuntimeCompanyPeriodicSideLatchState {
|
||||||
|
preferred_locomotive_engine_type_raw_u8: None,
|
||||||
|
city_connection_latch: false,
|
||||||
|
linked_transit_latch: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn periodic_boundary_applies_dividend_adjustment_from_annual_finance_policy() {
|
fn periodic_boundary_applies_dividend_adjustment_from_annual_finance_policy() {
|
||||||
let mut year_stat_family_qword_bits = vec![
|
let mut year_stat_family_qword_bits = vec![
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ Working rule:
|
||||||
`company_service_periodic_city_connection_finance_and_linked_transit_lanes`, using the now
|
`company_service_periodic_city_connection_finance_and_linked_transit_lanes`, using the now
|
||||||
save-native side-latch trio `0x0d17/0x0d18/0x0d56` as owned runtime state instead of leaving
|
save-native side-latch trio `0x0d17/0x0d18/0x0d56` as owned runtime state instead of leaving
|
||||||
that pass split across annual-finance readers and atlas notes.
|
that pass split across annual-finance readers and atlas notes.
|
||||||
- Move the periodic-boundary owner from passive imported side-latch state toward same-cycle
|
- Rehost the world-side `[world+0x4c74]` post-text owner lane so the temporary route-preference
|
||||||
service-owned refresh or reset behavior, so earlier periodic branches can eventually set those
|
override fed by company-side `0x0d17` can eventually move through a real runtime seam instead
|
||||||
lanes before annual finance consumes them.
|
of staying atlas-only.
|
||||||
- Keep widening selected-year world-owner state only when a full owning reader/rebuild family is
|
- Keep widening selected-year world-owner state only when a full owning reader/rebuild family is
|
||||||
grounded strongly enough to avoid one-off leaf guesses.
|
grounded strongly enough to avoid one-off leaf guesses.
|
||||||
|
|
||||||
|
|
@ -63,6 +63,9 @@ Working rule:
|
||||||
- That same side-latch trio now also has a runtime-owned service-state map and summary surface,
|
- That same side-latch trio now also has a runtime-owned service-state map and summary surface,
|
||||||
so later periodic company-service work can stop reading those lanes directly from imported
|
so later periodic company-service work can stop reading those lanes directly from imported
|
||||||
market/cache residue.
|
market/cache residue.
|
||||||
|
- The periodic-boundary owner now also clears the transient preferred-locomotive side latch every
|
||||||
|
cycle and reseeds the finance latches from market state where present, while preserving
|
||||||
|
side-latch-only company context when no market projection exists.
|
||||||
- Company cash, confiscation, and major governance effects now write through owner state instead of
|
- Company cash, confiscation, and major governance effects now write through owner state instead of
|
||||||
drifting from market/cache readers.
|
drifting from market/cache readers.
|
||||||
- Company credit rating, prime rate, book value per share, investor confidence, and management
|
- Company credit rating, prime rate, book value per share, investor confidence, and management
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue