Rehost first company stat-family reader seam
This commit is contained in:
parent
1e0f88bd62
commit
9ff4cac6fb
5 changed files with 158 additions and 14 deletions
|
|
@ -53,7 +53,10 @@ saved support/share-price/cache words, chairman salary lanes, calendar words, an
|
||||||
latches for each live company. That map now appears in runtime summaries and save-slice exports,
|
latches for each live company. That map now appears in runtime summaries and save-slice exports,
|
||||||
and it now also carries the first grounded stat-band root windows at `[company+0x0cfb]`,
|
and it now also carries the first grounded stat-band root windows at `[company+0x0cfb]`,
|
||||||
`[company+0x0d7f]`, and `[company+0x1c47]`, so later company stat-family / finance readers can
|
`[company+0x0d7f]`, and `[company+0x1c47]`, so later company stat-family / finance readers can
|
||||||
build on owned state instead of another round of single-field save-offset guesses. A checked-in
|
build on owned state instead of another round of single-field save-offset guesses. The first
|
||||||
|
runtime-side `0x2329` stat-family reader seam is now rehosted too for the currently grounded slots
|
||||||
|
`0x0d` (`current_cash`) and `0x1d` (`book_value_per_share`), so later annual-finance logic can
|
||||||
|
extend one shared reader family instead of hard-coding more direct field accesses. A checked-in
|
||||||
The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we
|
The working rule on the remaining frontier is explicit now too: when a lane is still ambiguous, we
|
||||||
should prefer rehosting the owning source state or the real reader/setter family rather than
|
should prefer rehosting the owning source state or the real reader/setter family rather than
|
||||||
guessing one more derived leaf field from nearby offsets. A checked-in
|
guessing one more derived leaf field from nearby offsets. A checked-in
|
||||||
|
|
|
||||||
|
|
@ -48,17 +48,19 @@ pub use runtime::{
|
||||||
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanProfile,
|
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanProfile,
|
||||||
RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyConditionTestScope,
|
RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyConditionTestScope,
|
||||||
RuntimeCompanyControllerKind, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
RuntimeCompanyControllerKind, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
||||||
RuntimeCompanyStatBandCandidate, RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess,
|
RuntimeCompanyStatBandCandidate, RuntimeCompanyStatSelector, RuntimeCompanyTarget,
|
||||||
RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition, RuntimeConditionComparator,
|
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,
|
||||||
RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry,
|
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
|
||||||
RuntimePackedEventCollectionSummary, RuntimePackedEventCompactControlSummary,
|
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||||
RuntimePackedEventConditionRowSummary, RuntimePackedEventGroupedEffectRowSummary,
|
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
|
||||||
RuntimePackedEventNegativeSentinelScopeSummary, RuntimePackedEventRecordSummary,
|
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
|
||||||
RuntimePackedEventTextBandSummary, RuntimePlayer, RuntimePlayerConditionTestScope,
|
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
|
||||||
RuntimePlayerTarget, RuntimeSaveProfileState, RuntimeServiceState, RuntimeState,
|
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeSaveProfileState,
|
||||||
RuntimeTerritory, RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric,
|
RuntimeServiceState, RuntimeState, RuntimeTerritory, RuntimeTerritoryMetric,
|
||||||
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate,
|
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts, RuntimeTrain,
|
||||||
RuntimeWorldRestoreState,
|
RuntimeWorldFinanceNeighborhoodCandidate, RuntimeWorldRestoreState,
|
||||||
|
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER, RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
|
||||||
|
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH, runtime_company_stat_value,
|
||||||
};
|
};
|
||||||
pub use smp::{
|
pub use smp::{
|
||||||
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,
|
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,16 @@ pub enum RuntimeChairmanMetric {
|
||||||
PurchasingPowerTotal,
|
PurchasingPowerTotal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct RuntimeCompanyStatSelector {
|
||||||
|
pub family_id: u32,
|
||||||
|
pub slot_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER: u32 = 0x2329;
|
||||||
|
pub const RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH: u32 = 0x0d;
|
||||||
|
pub const RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE: u32 = 0x1d;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum RuntimeTerritoryMetric {
|
pub enum RuntimeTerritoryMetric {
|
||||||
|
|
@ -1786,6 +1796,24 @@ impl RuntimeState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn runtime_company_stat_value(
|
||||||
|
state: &RuntimeState,
|
||||||
|
company_id: u32,
|
||||||
|
selector: RuntimeCompanyStatSelector,
|
||||||
|
) -> Option<i64> {
|
||||||
|
let company = state.companies.iter().find(|company| company.company_id == company_id)?;
|
||||||
|
match (selector.family_id, selector.slot_id) {
|
||||||
|
(RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER, RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH) => {
|
||||||
|
Some(company.current_cash)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
|
||||||
|
) => Some(company.book_value_per_share),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn rounded_cached_share_price_i64(raw_u32: u32) -> Option<i64> {
|
fn rounded_cached_share_price_i64(raw_u32: u32) -> Option<i64> {
|
||||||
let value = f32::from_bits(raw_u32);
|
let value = f32::from_bits(raw_u32);
|
||||||
if !value.is_finite() {
|
if !value.is_finite() {
|
||||||
|
|
@ -3669,4 +3697,112 @@ mod tests {
|
||||||
assert_eq!(state.chairman_profiles[0].net_worth_total, 100);
|
assert_eq!(state.chairman_profiles[0].net_worth_total, 100);
|
||||||
assert_eq!(state.chairman_profiles[0].purchasing_power_total, 130);
|
assert_eq!(state.chairman_profiles[0].purchasing_power_total, 130);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reads_grounded_company_stat_family_slots_from_runtime_state() {
|
||||||
|
let 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: 7,
|
||||||
|
current_cash: 125_000,
|
||||||
|
debt: 0,
|
||||||
|
credit_rating_score: None,
|
||||||
|
prime_rate: None,
|
||||||
|
active: true,
|
||||||
|
available_track_laying_capacity: None,
|
||||||
|
controller_kind: RuntimeCompanyControllerKind::Unknown,
|
||||||
|
linked_chairman_profile_id: None,
|
||||||
|
book_value_per_share: 2_620,
|
||||||
|
investor_confidence: 0,
|
||||||
|
management_attitude: 0,
|
||||||
|
takeover_cooldown_year: None,
|
||||||
|
merger_cooldown_year: None,
|
||||||
|
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||||
|
}],
|
||||||
|
selected_company_id: None,
|
||||||
|
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::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
runtime_company_stat_value(
|
||||||
|
&state,
|
||||||
|
7,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some(125_000)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
runtime_company_stat_value(
|
||||||
|
&state,
|
||||||
|
7,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
slot_id: RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some(2_620)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
runtime_company_stat_value(
|
||||||
|
&state,
|
||||||
|
7,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
slot_id: 0x2b,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
runtime_company_stat_value(
|
||||||
|
&state,
|
||||||
|
99,
|
||||||
|
RuntimeCompanyStatSelector {
|
||||||
|
family_id: RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER,
|
||||||
|
slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,8 @@ The highest-value next passes are now:
|
||||||
outstanding-shares, support/share-price/cache words, salary lanes, calendar words, connection
|
outstanding-shares, support/share-price/cache words, salary lanes, calendar words, connection
|
||||||
latches, and the first grounded stat-band root windows at `[company+0x0cfb]`, `[company+0x0d7f]`,
|
latches, and the first grounded stat-band root windows at `[company+0x0cfb]`, `[company+0x0d7f]`,
|
||||||
and `[company+0x1c47]` for each live company, so later finance/stat-family readers can attach to
|
and `[company+0x1c47]` for each live company, so later finance/stat-family readers can attach to
|
||||||
owned runtime data instead of one more guessed save offset
|
owned runtime data instead of one more guessed save offset; the first runtime-side `0x2329`
|
||||||
|
stat-family reader seam is now also rehosted for slots `0x0d` and `0x1d`
|
||||||
- the project rule on the remaining closure work is now explicit too: when one runtime-facing field
|
- the project rule on the remaining closure work is now explicit too: when one runtime-facing field
|
||||||
is still ambiguous, prefer rehosting the owning source state or real reader/setter family first
|
is still ambiguous, prefer rehosting the owning source state or real reader/setter family first
|
||||||
instead of guessing another derived leaf field from neighboring raw offsets
|
instead of guessing another derived leaf field from neighboring raw offsets
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,9 @@ field when that richer owning-state path is blocked. Richer runtime ownership sh
|
||||||
where later descriptor, stat-family, or simulation work needs more than the current event-owned
|
where later descriptor, stat-family, or simulation work needs more than the current event-owned
|
||||||
roster. The current owned company-side roster now includes not just the market/cache lanes but also
|
roster. The current owned company-side roster now includes not just the market/cache lanes but also
|
||||||
the first grounded stat-band root windows at `[company+0x0cfb]`, `[company+0x0d7f]`, and
|
the first grounded stat-band root windows at `[company+0x0cfb]`, `[company+0x0d7f]`, and
|
||||||
`[company+0x1c47]`, so later finance readers can target saved owner state directly.
|
`[company+0x1c47]`, and the first runtime-side `0x2329` stat-family reader seam is now rehosted
|
||||||
|
for slots `0x0d` and `0x1d`, so later finance readers can target saved owner state and one shared
|
||||||
|
reader family directly.
|
||||||
|
|
||||||
## Why This Boundary
|
## Why This Boundary
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue