Rehost save-native company market cache state
This commit is contained in:
parent
77c847afba
commit
5198f80cd9
9 changed files with 630 additions and 79 deletions
|
|
@ -46,7 +46,12 @@ holdings-at-share-price / cached purchasing-power comparisons. The same fixed `0
|
|||
block is now probed for both the grounded issue-`0x37` pair at `[world+0x29/+0x2d]` and the
|
||||
separate six-float economic tuning band, but current atlas evidence still keeps that editor-facing
|
||||
tuning family distinct from the governance issue lanes behind investor confidence and prime-rate
|
||||
math. A checked-in
|
||||
math. The next shared company-side slice is now rehosted too: save-native company direct records
|
||||
flow into a typed company market/cache map on runtime service state, carrying outstanding shares,
|
||||
saved support/share-price/cache words, chairman salary lanes, calendar words, and connection
|
||||
latches for each live company. That map now appears in runtime summaries and save-slice exports,
|
||||
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
|
||||
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
|
||||
guessing one more derived leaf field from nearby offsets. A checked-in
|
||||
|
|
|
|||
|
|
@ -84,6 +84,14 @@ pub struct ExpectedRuntimeSummary {
|
|||
#[serde(default)]
|
||||
pub active_company_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub company_market_state_owner_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub selected_company_outstanding_shares: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub selected_company_cached_share_price_value_f32_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub selected_company_mutable_support_scalar_value_f32_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub player_count: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub chairman_profile_count: Option<usize>,
|
||||
|
|
@ -541,6 +549,46 @@ impl ExpectedRuntimeSummary {
|
|||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.company_market_state_owner_count {
|
||||
if actual.company_market_state_owner_count != count {
|
||||
mismatches.push(format!(
|
||||
"company_market_state_owner_count mismatch: expected {count}, got {}",
|
||||
actual.company_market_state_owner_count
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = self.selected_company_outstanding_shares {
|
||||
if actual.selected_company_outstanding_shares != Some(value) {
|
||||
mismatches.push(format!(
|
||||
"selected_company_outstanding_shares mismatch: expected {value}, got {:?}",
|
||||
actual.selected_company_outstanding_shares
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = &self.selected_company_cached_share_price_value_f32_text {
|
||||
if actual
|
||||
.selected_company_cached_share_price_value_f32_text
|
||||
.as_ref()
|
||||
!= Some(value)
|
||||
{
|
||||
mismatches.push(format!(
|
||||
"selected_company_cached_share_price_value_f32_text mismatch: expected {value:?}, got {:?}",
|
||||
actual.selected_company_cached_share_price_value_f32_text
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(value) = &self.selected_company_mutable_support_scalar_value_f32_text {
|
||||
if actual
|
||||
.selected_company_mutable_support_scalar_value_f32_text
|
||||
.as_ref()
|
||||
!= Some(value)
|
||||
{
|
||||
mismatches.push(format!(
|
||||
"selected_company_mutable_support_scalar_value_f32_text mismatch: expected {value:?}, got {:?}",
|
||||
actual.selected_company_mutable_support_scalar_value_f32_text
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(count) = self.player_count {
|
||||
if actual.player_count != count {
|
||||
mismatches.push(format!(
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use crate::persistence::{load_runtime_snapshot_document, validate_runtime_snapsh
|
|||
use crate::{
|
||||
CalendarPoint, RuntimeCargoCatalogEntry, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
|
||||
RuntimeChairmanProfile, RuntimeChairmanTarget, RuntimeCompany,
|
||||
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyTarget,
|
||||
RuntimeCondition, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
|
||||
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||
RuntimeCompanyConditionTestScope, RuntimeCompanyControllerKind, RuntimeCompanyMarketState,
|
||||
RuntimeCompanyTarget, RuntimeCondition, RuntimeEffect, RuntimeEventRecord,
|
||||
RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
|
||||
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
|
||||
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary,
|
||||
|
|
@ -99,6 +99,8 @@ struct SaveSliceProjection {
|
|||
has_company_projection: bool,
|
||||
has_company_selection_override: bool,
|
||||
selected_company_id: Option<u32>,
|
||||
company_market_state: BTreeMap<u32, RuntimeCompanyMarketState>,
|
||||
has_company_market_projection: bool,
|
||||
chairman_profiles: Vec<RuntimeChairmanProfile>,
|
||||
has_chairman_projection: bool,
|
||||
has_chairman_selection_override: bool,
|
||||
|
|
@ -308,7 +310,10 @@ pub fn project_save_slice_to_runtime_state_import(
|
|||
territory_runtime_variables: BTreeMap::new(),
|
||||
world_scalar_overrides: projection.world_scalar_overrides,
|
||||
special_conditions: projection.special_conditions,
|
||||
service_state: RuntimeServiceState::default(),
|
||||
service_state: RuntimeServiceState {
|
||||
company_market_state: projection.company_market_state,
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
state.validate()?;
|
||||
|
||||
|
|
@ -410,7 +415,14 @@ pub fn project_save_slice_overlay_to_runtime_state_import(
|
|||
territory_runtime_variables: base_state.territory_runtime_variables.clone(),
|
||||
world_scalar_overrides: base_state.world_scalar_overrides.clone(),
|
||||
special_conditions: projection.special_conditions,
|
||||
service_state: base_state.service_state.clone(),
|
||||
service_state: RuntimeServiceState {
|
||||
company_market_state: if projection.has_company_market_projection {
|
||||
projection.company_market_state
|
||||
} else {
|
||||
base_state.service_state.company_market_state.clone()
|
||||
},
|
||||
..base_state.service_state.clone()
|
||||
},
|
||||
};
|
||||
state.validate()?;
|
||||
|
||||
|
|
@ -915,8 +927,14 @@ fn project_save_slice_components(
|
|||
None
|
||||
};
|
||||
|
||||
let (companies, has_company_projection, has_company_selection_override, selected_company_id) =
|
||||
if let Some(roster) = &save_slice.company_roster {
|
||||
let (
|
||||
companies,
|
||||
has_company_projection,
|
||||
has_company_selection_override,
|
||||
selected_company_id,
|
||||
company_market_state,
|
||||
has_company_market_projection,
|
||||
) = if let Some(roster) = &save_slice.company_roster {
|
||||
metadata.insert(
|
||||
"save_slice.company_roster_source_kind".to_string(),
|
||||
roster.source_kind.clone(),
|
||||
|
|
@ -929,6 +947,20 @@ fn project_save_slice_components(
|
|||
"save_slice.company_roster_entry_count".to_string(),
|
||||
roster.observed_entry_count.to_string(),
|
||||
);
|
||||
let market_state = roster
|
||||
.entries
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
entry
|
||||
.market_state
|
||||
.as_ref()
|
||||
.map(|state| (entry.company_id, state.clone()))
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
metadata.insert(
|
||||
"save_slice.company_market_state_owner_count".to_string(),
|
||||
market_state.len().to_string(),
|
||||
);
|
||||
if let Some(selected_company_id) = roster.selected_company_id {
|
||||
metadata.insert(
|
||||
"save_slice.selected_company_id".to_string(),
|
||||
|
|
@ -941,6 +973,8 @@ fn project_save_slice_components(
|
|||
false,
|
||||
roster.selected_company_id.is_some(),
|
||||
roster.selected_company_id,
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
|
|
@ -968,10 +1002,12 @@ fn project_save_slice_components(
|
|||
true,
|
||||
roster.selected_company_id.is_some(),
|
||||
roster.selected_company_id,
|
||||
market_state,
|
||||
true,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(Vec::new(), false, false, None)
|
||||
(Vec::new(), false, false, None, BTreeMap::new(), false)
|
||||
};
|
||||
|
||||
let (
|
||||
|
|
@ -1112,6 +1148,8 @@ fn project_save_slice_components(
|
|||
has_company_projection,
|
||||
has_company_selection_override,
|
||||
selected_company_id,
|
||||
company_market_state,
|
||||
has_company_market_projection,
|
||||
chairman_profiles,
|
||||
has_chairman_projection,
|
||||
has_chairman_selection_override,
|
||||
|
|
@ -4952,6 +4990,22 @@ mod tests {
|
|||
management_attitude: 58,
|
||||
takeover_cooldown_year: Some(1839),
|
||||
merger_cooldown_year: Some(1838),
|
||||
market_state: Some(crate::RuntimeCompanyMarketState {
|
||||
outstanding_shares: 20_000,
|
||||
mutable_support_scalar_raw_u32: 0x3f99999a,
|
||||
young_company_support_scalar_raw_u32: 0x42700000,
|
||||
support_progress_word: 12,
|
||||
recent_per_share_subscore_raw_u32: 0x420c0000,
|
||||
cached_share_price_raw_u32: 0x42200000,
|
||||
chairman_salary_baseline: 24,
|
||||
chairman_salary_current: 30,
|
||||
founding_year: 1831,
|
||||
last_bankruptcy_year: 0,
|
||||
current_issue_calendar_word: 5,
|
||||
prior_issue_calendar_word: 4,
|
||||
city_connection_latch: true,
|
||||
linked_transit_latch: false,
|
||||
}),
|
||||
},
|
||||
crate::SmpLoadedCompanyRosterEntry {
|
||||
company_id: 2,
|
||||
|
|
@ -4976,6 +5030,22 @@ mod tests {
|
|||
management_attitude: 31,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
market_state: Some(crate::RuntimeCompanyMarketState {
|
||||
outstanding_shares: 18_000,
|
||||
mutable_support_scalar_raw_u32: 0x3f4ccccd,
|
||||
young_company_support_scalar_raw_u32: 0x42580000,
|
||||
support_progress_word: 9,
|
||||
recent_per_share_subscore_raw_u32: 0x41f00000,
|
||||
cached_share_price_raw_u32: 0x41f80000,
|
||||
chairman_salary_baseline: 20,
|
||||
chairman_salary_current: 22,
|
||||
founding_year: 1833,
|
||||
last_bankruptcy_year: 0,
|
||||
current_issue_calendar_word: 3,
|
||||
prior_issue_calendar_word: 2,
|
||||
city_connection_latch: false,
|
||||
linked_transit_latch: true,
|
||||
}),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -6073,6 +6143,16 @@ mod tests {
|
|||
assert_eq!(import.state.selected_chairman_profile_id, Some(1));
|
||||
assert_eq!(import.state.companies[0].book_value_per_share, 2620);
|
||||
assert_eq!(import.state.chairman_profiles[0].current_cash, 500);
|
||||
assert_eq!(import.state.service_state.company_market_state.len(), 2);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.service_state
|
||||
.company_market_state
|
||||
.get(&1)
|
||||
.map(|state| state.cached_share_price_raw_u32),
|
||||
Some(0x42200000)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -6149,6 +6229,15 @@ mod tests {
|
|||
assert_eq!(import.state.chairman_profiles.len(), 2);
|
||||
assert_eq!(import.state.selected_chairman_profile_id, Some(1));
|
||||
assert_eq!(import.state.territories, base_state.territories);
|
||||
assert_eq!(
|
||||
import
|
||||
.state
|
||||
.service_state
|
||||
.company_market_state
|
||||
.get(&2)
|
||||
.map(|state| state.linked_transit_latch),
|
||||
Some(true)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -6216,6 +6305,28 @@ mod tests {
|
|||
},
|
||||
],
|
||||
selected_chairman_profile_id: Some(9),
|
||||
service_state: RuntimeServiceState {
|
||||
company_market_state: BTreeMap::from([(
|
||||
42,
|
||||
crate::RuntimeCompanyMarketState {
|
||||
outstanding_shares: 30_000,
|
||||
mutable_support_scalar_raw_u32: 0x3f19999a,
|
||||
young_company_support_scalar_raw_u32: 0x42580000,
|
||||
support_progress_word: 8,
|
||||
recent_per_share_subscore_raw_u32: 0x42000000,
|
||||
cached_share_price_raw_u32: 0x42180000,
|
||||
chairman_salary_baseline: 21,
|
||||
chairman_salary_current: 24,
|
||||
founding_year: 1834,
|
||||
last_bankruptcy_year: 0,
|
||||
current_issue_calendar_word: 4,
|
||||
prior_issue_calendar_word: 3,
|
||||
city_connection_latch: false,
|
||||
linked_transit_latch: true,
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
..state()
|
||||
};
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
|
|
@ -6263,6 +6374,10 @@ mod tests {
|
|||
assert_eq!(import.state.selected_company_id, Some(1));
|
||||
assert_eq!(import.state.chairman_profiles, base_state.chairman_profiles);
|
||||
assert_eq!(import.state.selected_chairman_profile_id, Some(1));
|
||||
assert_eq!(
|
||||
import.state.service_state.company_market_state,
|
||||
base_state.service_state.company_market_state
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -13371,6 +13486,7 @@ mod tests {
|
|||
trigger_dispatch_counts: BTreeMap::new(),
|
||||
total_event_record_services: 4,
|
||||
dirty_rerun_count: 2,
|
||||
company_market_state: BTreeMap::new(),
|
||||
},
|
||||
};
|
||||
let save_slice = SmpLoadedSaveSlice {
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ pub use runtime::{
|
|||
RuntimeCargoCatalogEntry, RuntimeCargoClass, RuntimeCargoPriceTarget,
|
||||
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanProfile,
|
||||
RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyConditionTestScope,
|
||||
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget,
|
||||
RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount, RuntimeCondition,
|
||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord, RuntimeEventRecordTemplate,
|
||||
RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||
RuntimeCompanyControllerKind, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
||||
RuntimeCompanyTarget, RuntimeCompanyTerritoryAccess, RuntimeCompanyTerritoryTrackPieceCount,
|
||||
RuntimeCondition, RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecord,
|
||||
RuntimeEventRecordTemplate, RuntimeLocomotiveCatalogEntry, RuntimePackedEventCollectionSummary,
|
||||
RuntimePackedEventCompactControlSummary, RuntimePackedEventConditionRowSummary,
|
||||
RuntimePackedEventGroupedEffectRowSummary, RuntimePackedEventNegativeSentinelScopeSummary,
|
||||
RuntimePackedEventRecordSummary, RuntimePackedEventTextBandSummary, RuntimePlayer,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,38 @@ pub struct RuntimeCompany {
|
|||
pub track_piece_counts: RuntimeTrackPieceCounts,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub struct RuntimeCompanyMarketState {
|
||||
#[serde(default)]
|
||||
pub outstanding_shares: u32,
|
||||
#[serde(default)]
|
||||
pub mutable_support_scalar_raw_u32: u32,
|
||||
#[serde(default)]
|
||||
pub young_company_support_scalar_raw_u32: u32,
|
||||
#[serde(default)]
|
||||
pub support_progress_word: u32,
|
||||
#[serde(default)]
|
||||
pub recent_per_share_subscore_raw_u32: u32,
|
||||
#[serde(default)]
|
||||
pub cached_share_price_raw_u32: u32,
|
||||
#[serde(default)]
|
||||
pub chairman_salary_baseline: u32,
|
||||
#[serde(default)]
|
||||
pub chairman_salary_current: u32,
|
||||
#[serde(default)]
|
||||
pub founding_year: u32,
|
||||
#[serde(default)]
|
||||
pub last_bankruptcy_year: u32,
|
||||
#[serde(default)]
|
||||
pub current_issue_calendar_word: u32,
|
||||
#[serde(default)]
|
||||
pub prior_issue_calendar_word: u32,
|
||||
#[serde(default)]
|
||||
pub city_connection_latch: bool,
|
||||
#[serde(default)]
|
||||
pub linked_transit_latch: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct RuntimeTrackPieceCounts {
|
||||
#[serde(default)]
|
||||
|
|
@ -798,6 +830,8 @@ pub struct RuntimeServiceState {
|
|||
pub total_event_record_services: u64,
|
||||
#[serde(default)]
|
||||
pub dirty_rerun_count: u64,
|
||||
#[serde(default)]
|
||||
pub company_market_state: BTreeMap<u32, RuntimeCompanyMarketState>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
|
|
@ -1629,6 +1663,14 @@ impl RuntimeState {
|
|||
}
|
||||
}
|
||||
}
|
||||
for company_id in self.service_state.company_market_state.keys() {
|
||||
if !seen_company_ids.contains(company_id) {
|
||||
return Err(format!(
|
||||
"service_state.company_market_state references unknown company_id {}",
|
||||
company_id
|
||||
));
|
||||
}
|
||||
}
|
||||
for (player_id, vars) in &self.player_runtime_variables {
|
||||
if !seen_player_ids.contains(player_id) {
|
||||
return Err(format!(
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ use sha2::{Digest, Sha256};
|
|||
use crate::{
|
||||
RuntimeCargoClass, RuntimeCargoPriceTarget, RuntimeCargoProductionTarget,
|
||||
RuntimeChairmanMetric, RuntimeChairmanTarget, RuntimeCompanyConditionTestScope,
|
||||
RuntimeCompanyControllerKind, RuntimeCompanyMetric, RuntimeCompanyTarget, RuntimeCondition,
|
||||
RuntimeConditionComparator, RuntimeEffect, RuntimeEventRecordTemplate,
|
||||
RuntimePlayerConditionTestScope, RuntimePlayerTarget, RuntimeTerritoryMetric,
|
||||
RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
RuntimeCompanyControllerKind, RuntimeCompanyMarketState, RuntimeCompanyMetric,
|
||||
RuntimeCompanyTarget, RuntimeCondition, RuntimeConditionComparator, RuntimeEffect,
|
||||
RuntimeEventRecordTemplate, RuntimePlayerConditionTestScope, RuntimePlayerTarget,
|
||||
RuntimeTerritoryMetric, RuntimeTerritoryTarget, RuntimeTrackMetric, RuntimeTrackPieceCounts,
|
||||
};
|
||||
|
||||
pub const SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION: u32 = 0x03ec;
|
||||
|
|
@ -2196,6 +2196,8 @@ pub struct SmpLoadedCompanyRosterEntry {
|
|||
pub takeover_cooldown_year: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub merger_cooldown_year: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub market_state: Option<RuntimeCompanyMarketState>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -3329,20 +3331,36 @@ const SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET: usize = 0x14f;
|
|||
const SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET: usize = 0x15f;
|
||||
const SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET: usize = 0x157;
|
||||
const SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET: usize = 0x163;
|
||||
const SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET: usize = 0x16b;
|
||||
const SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET: usize = 0x173;
|
||||
const SAVE_COMPANY_RECORD_TAKEOVER_COOLDOWN_OFFSET: usize = 0x289;
|
||||
const SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET: usize = 0x0d18;
|
||||
const SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET: usize = 0x0d07;
|
||||
const SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET: usize = 0x0d59;
|
||||
const SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET: usize = 0x0d56;
|
||||
const SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET: usize = 0x0d19;
|
||||
const SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET: usize = 0x0d7b;
|
||||
const SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET: usize = 0x7680;
|
||||
const SAVE_COMPANY_RECORD_SCALAR_CANDIDATE_FIELDS: [(&str, usize); 7] = [
|
||||
("mutable_support_scalar", 0x4f),
|
||||
("young_company_support_scalar", 0x57),
|
||||
("support_progress_word", 0x0d07),
|
||||
("recent_per_share_subscore", 0x0d19),
|
||||
(
|
||||
"support_progress_word",
|
||||
SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET,
|
||||
),
|
||||
(
|
||||
"recent_per_share_subscore",
|
||||
SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET,
|
||||
),
|
||||
("cached_share_price", 0x0d7b),
|
||||
("current_issue_calendar_word", 0x16b),
|
||||
("prior_issue_calendar_word", 0x173),
|
||||
(
|
||||
"current_issue_calendar_word",
|
||||
SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET,
|
||||
),
|
||||
(
|
||||
"prior_issue_calendar_word",
|
||||
SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET,
|
||||
),
|
||||
];
|
||||
const SAVE_COMPANY_RECORD_POST_CAPACITY_CANDIDATE_FIELDS: [(&str, usize); 6] = [
|
||||
("post_capacity_word_1", 0x7684),
|
||||
|
|
@ -3398,9 +3416,65 @@ fn parse_save_company_roster_probe(
|
|||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_LINKED_CHAIRMAN_OFFSET,
|
||||
)?;
|
||||
let outstanding_shares = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_OUTSTANDING_SHARES_OFFSET,
|
||||
)?;
|
||||
let debt = parse_save_company_total_debt(bytes, record_offset)?;
|
||||
let available_track_laying_capacity =
|
||||
parse_save_company_available_track_laying_capacity(bytes, record_offset)?;
|
||||
let mutable_support_scalar_raw_u32 = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET,
|
||||
)?;
|
||||
let young_company_support_scalar_raw_u32 = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET,
|
||||
)?;
|
||||
let support_progress_word = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET,
|
||||
)?;
|
||||
let recent_per_share_subscore_raw_u32 = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET,
|
||||
)?;
|
||||
let cached_share_price_raw_u32 = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET,
|
||||
)?;
|
||||
let chairman_salary_baseline = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET,
|
||||
)?;
|
||||
let chairman_salary_current = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET,
|
||||
)?;
|
||||
let founding_year = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET,
|
||||
)?;
|
||||
let last_bankruptcy_year = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET,
|
||||
)?;
|
||||
let current_issue_calendar_word = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET,
|
||||
)?;
|
||||
let prior_issue_calendar_word = read_u32_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET,
|
||||
)?;
|
||||
let city_connection_latch = read_u8_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET,
|
||||
)? != 0;
|
||||
let linked_transit_latch = read_u8_at(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET,
|
||||
)? != 0;
|
||||
let merger_cooldown_year = parse_nonzero_u32(
|
||||
bytes,
|
||||
record_offset + SAVE_COMPANY_RECORD_MERGER_COOLDOWN_OFFSET,
|
||||
|
|
@ -3425,6 +3499,22 @@ fn parse_save_company_roster_probe(
|
|||
management_attitude: 0,
|
||||
takeover_cooldown_year,
|
||||
merger_cooldown_year,
|
||||
market_state: Some(RuntimeCompanyMarketState {
|
||||
outstanding_shares,
|
||||
mutable_support_scalar_raw_u32,
|
||||
young_company_support_scalar_raw_u32,
|
||||
support_progress_word,
|
||||
recent_per_share_subscore_raw_u32,
|
||||
cached_share_price_raw_u32,
|
||||
chairman_salary_baseline,
|
||||
chairman_salary_current,
|
||||
founding_year,
|
||||
last_bankruptcy_year,
|
||||
current_issue_calendar_word,
|
||||
prior_issue_calendar_word,
|
||||
city_connection_latch,
|
||||
linked_transit_latch,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -15386,7 +15476,31 @@ mod tests {
|
|||
.copy_from_slice(&0x000061aau32.to_le_bytes());
|
||||
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x000061abu32.to_le_bytes());
|
||||
|
||||
for (index, (name, linked, merger, takeover, bond_count, _debt, track_capacity)) in [
|
||||
for (
|
||||
index,
|
||||
(
|
||||
name,
|
||||
linked,
|
||||
merger,
|
||||
takeover,
|
||||
bond_count,
|
||||
_debt,
|
||||
track_capacity,
|
||||
mutable_support_scalar_raw_u32,
|
||||
young_company_support_scalar_raw_u32,
|
||||
support_progress_word,
|
||||
recent_per_share_subscore_raw_u32,
|
||||
cached_share_price_raw_u32,
|
||||
chairman_salary_baseline,
|
||||
chairman_salary_current,
|
||||
founding_year,
|
||||
last_bankruptcy_year,
|
||||
current_issue_calendar_word,
|
||||
prior_issue_calendar_word,
|
||||
city_connection_latch,
|
||||
linked_transit_latch,
|
||||
),
|
||||
) in [
|
||||
(
|
||||
"Company One",
|
||||
1u32,
|
||||
|
|
@ -15395,8 +15509,42 @@ mod tests {
|
|||
2u8,
|
||||
1_000_000u32,
|
||||
Some(603i32),
|
||||
0x3f800000u32,
|
||||
0x42340000u32,
|
||||
17u32,
|
||||
0x41f00000u32,
|
||||
0x426c0000u32,
|
||||
24u32,
|
||||
31u32,
|
||||
1842u32,
|
||||
1851u32,
|
||||
7u32,
|
||||
6u32,
|
||||
true,
|
||||
false,
|
||||
),
|
||||
(
|
||||
"Company Two",
|
||||
2u32,
|
||||
0u32,
|
||||
1871u32,
|
||||
1u8,
|
||||
500_000u32,
|
||||
None,
|
||||
0x40000000u32,
|
||||
0x42700000u32,
|
||||
33u32,
|
||||
0x42000000u32,
|
||||
0x42780000u32,
|
||||
28u32,
|
||||
36u32,
|
||||
1845u32,
|
||||
0u32,
|
||||
3u32,
|
||||
2u32,
|
||||
false,
|
||||
true,
|
||||
),
|
||||
("Company Two", 2u32, 0u32, 1871u32, 1u8, 500_000u32, None),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
|
|
@ -15412,6 +15560,12 @@ mod tests {
|
|||
bytes[record_offset + SAVE_COMPANY_RECORD_ACTIVE_OFFSET] = 1;
|
||||
bytes[record_offset + 0x47..record_offset + 0x4b]
|
||||
.copy_from_slice(&20000u32.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_SUPPORT_SCALAR_OFFSET + 4]
|
||||
.copy_from_slice(&mutable_support_scalar_raw_u32.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_COMPANY_VALUE_OFFSET + 4]
|
||||
.copy_from_slice(&young_company_support_scalar_raw_u32.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_BOND_COUNT_OFFSET] = bond_count;
|
||||
for slot_index in 0..bond_count as usize {
|
||||
let slot_offset = record_offset
|
||||
|
|
@ -15432,6 +15586,37 @@ mod tests {
|
|||
bytes[record_offset + SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_TRACK_LAYING_CAPACITY_OFFSET + 4]
|
||||
.copy_from_slice(&raw_capacity.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_SUPPORT_PROGRESS_OFFSET + 4]
|
||||
.copy_from_slice(&support_progress_word.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_RECENT_PER_SHARE_SUBSCORE_OFFSET + 4]
|
||||
.copy_from_slice(&recent_per_share_subscore_raw_u32.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_CACHED_SHARE_PRICE_OFFSET + 4]
|
||||
.copy_from_slice(&cached_share_price_raw_u32.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_BASELINE_OFFSET + 4]
|
||||
.copy_from_slice(&chairman_salary_baseline.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_CHAIRMAN_SALARY_CURRENT_OFFSET + 4]
|
||||
.copy_from_slice(&chairman_salary_current.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_FOUNDING_YEAR_OFFSET + 4]
|
||||
.copy_from_slice(&founding_year.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_LAST_BANKRUPTCY_YEAR_OFFSET + 4]
|
||||
.copy_from_slice(&last_bankruptcy_year.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_CURRENT_ISSUE_CALENDAR_OFFSET + 4]
|
||||
.copy_from_slice(¤t_issue_calendar_word.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET
|
||||
..record_offset + SAVE_COMPANY_RECORD_PRIOR_ISSUE_CALENDAR_OFFSET + 4]
|
||||
.copy_from_slice(&prior_issue_calendar_word.to_le_bytes());
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_CITY_CONNECTION_LATCH_OFFSET] =
|
||||
u8::from(city_connection_latch);
|
||||
bytes[record_offset + SAVE_COMPANY_RECORD_LINKED_TRANSIT_LATCH_OFFSET] =
|
||||
u8::from(linked_transit_latch);
|
||||
}
|
||||
|
||||
let header_probe = parse_save_company_collection_header_probe(
|
||||
|
|
@ -15481,11 +15666,40 @@ mod tests {
|
|||
assert_eq!(roster.entries[0].debt, 1_000_000);
|
||||
assert_eq!(roster.entries[0].available_track_laying_capacity, Some(603));
|
||||
assert_eq!(roster.entries[0].merger_cooldown_year, Some(1862));
|
||||
let market_state = roster.entries[0]
|
||||
.market_state
|
||||
.as_ref()
|
||||
.expect("company market state should load");
|
||||
assert_eq!(market_state.outstanding_shares, 20_000);
|
||||
assert_eq!(market_state.mutable_support_scalar_raw_u32, 0x3f800000);
|
||||
assert_eq!(
|
||||
market_state.young_company_support_scalar_raw_u32,
|
||||
0x42340000
|
||||
);
|
||||
assert_eq!(market_state.support_progress_word, 17);
|
||||
assert_eq!(market_state.recent_per_share_subscore_raw_u32, 0x41f00000);
|
||||
assert_eq!(market_state.cached_share_price_raw_u32, 0x426c0000);
|
||||
assert_eq!(market_state.chairman_salary_baseline, 24);
|
||||
assert_eq!(market_state.chairman_salary_current, 31);
|
||||
assert_eq!(market_state.founding_year, 1842);
|
||||
assert_eq!(market_state.last_bankruptcy_year, 1851);
|
||||
assert_eq!(market_state.current_issue_calendar_word, 7);
|
||||
assert_eq!(market_state.prior_issue_calendar_word, 6);
|
||||
assert!(market_state.city_connection_latch);
|
||||
assert!(!market_state.linked_transit_latch);
|
||||
assert_eq!(roster.entries[1].company_id, 2);
|
||||
assert_eq!(roster.entries[1].linked_chairman_profile_id, Some(2));
|
||||
assert_eq!(roster.entries[1].debt, 500_000);
|
||||
assert_eq!(roster.entries[1].available_track_laying_capacity, None);
|
||||
assert_eq!(roster.entries[1].takeover_cooldown_year, Some(1871));
|
||||
let second_market_state = roster.entries[1]
|
||||
.market_state
|
||||
.as_ref()
|
||||
.expect("second company market state should load");
|
||||
assert_eq!(second_market_state.current_issue_calendar_word, 3);
|
||||
assert_eq!(second_market_state.prior_issue_calendar_word, 2);
|
||||
assert!(!second_market_state.city_connection_latch);
|
||||
assert!(second_market_state.linked_transit_latch);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{CalendarPoint, RuntimeState};
|
||||
|
||||
fn raw_u32_to_f32_text(raw: u32) -> String {
|
||||
format!("{:.6}", f32::from_bits(raw))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimeSummary {
|
||||
pub calendar: CalendarPoint,
|
||||
|
|
@ -39,6 +43,10 @@ pub struct RuntimeSummary {
|
|||
pub metadata_count: usize,
|
||||
pub company_count: usize,
|
||||
pub active_company_count: usize,
|
||||
pub company_market_state_owner_count: usize,
|
||||
pub selected_company_outstanding_shares: Option<u32>,
|
||||
pub selected_company_cached_share_price_value_f32_text: Option<String>,
|
||||
pub selected_company_mutable_support_scalar_value_f32_text: Option<String>,
|
||||
pub player_count: usize,
|
||||
pub chairman_profile_count: usize,
|
||||
pub active_chairman_profile_count: usize,
|
||||
|
|
@ -122,6 +130,9 @@ pub struct RuntimeSummary {
|
|||
|
||||
impl RuntimeSummary {
|
||||
pub fn from_state(state: &RuntimeState) -> Self {
|
||||
let selected_company_market_state = state
|
||||
.selected_company_id
|
||||
.and_then(|company_id| state.service_state.company_market_state.get(&company_id));
|
||||
Self {
|
||||
calendar: state.calendar,
|
||||
calendar_projection_source: state.metadata.get("save_slice.calendar_source").cloned(),
|
||||
|
|
@ -214,6 +225,15 @@ impl RuntimeSummary {
|
|||
.iter()
|
||||
.filter(|company| company.active)
|
||||
.count(),
|
||||
company_market_state_owner_count: state.service_state.company_market_state.len(),
|
||||
selected_company_outstanding_shares: selected_company_market_state
|
||||
.map(|market_state| market_state.outstanding_shares),
|
||||
selected_company_cached_share_price_value_f32_text: selected_company_market_state
|
||||
.map(|market_state| raw_u32_to_f32_text(market_state.cached_share_price_raw_u32)),
|
||||
selected_company_mutable_support_scalar_value_f32_text: selected_company_market_state
|
||||
.map(|market_state| {
|
||||
raw_u32_to_f32_text(market_state.mutable_support_scalar_raw_u32)
|
||||
}),
|
||||
player_count: state.players.len(),
|
||||
chairman_profile_count: state.chairman_profiles.len(),
|
||||
active_chairman_profile_count: state
|
||||
|
|
@ -1765,4 +1785,100 @@ mod tests {
|
|||
let summary = RuntimeSummary::from_state(&state);
|
||||
assert_eq!(summary.packed_event_blocked_shell_owned_descriptor_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarizes_selected_company_market_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: 1,
|
||||
current_cash: 0,
|
||||
debt: 0,
|
||||
credit_rating_score: None,
|
||||
prime_rate: None,
|
||||
active: true,
|
||||
available_track_laying_capacity: None,
|
||||
controller_kind: crate::RuntimeCompanyControllerKind::Unknown,
|
||||
linked_chairman_profile_id: None,
|
||||
book_value_per_share: 0,
|
||||
investor_confidence: 0,
|
||||
management_attitude: 0,
|
||||
takeover_cooldown_year: None,
|
||||
merger_cooldown_year: None,
|
||||
track_piece_counts: RuntimeTrackPieceCounts::default(),
|
||||
}],
|
||||
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_market_state: BTreeMap::from([(
|
||||
1,
|
||||
crate::RuntimeCompanyMarketState {
|
||||
outstanding_shares: 20_000,
|
||||
mutable_support_scalar_raw_u32: 0x3f800000,
|
||||
young_company_support_scalar_raw_u32: 0x42340000,
|
||||
support_progress_word: 12,
|
||||
recent_per_share_subscore_raw_u32: 0x420c0000,
|
||||
cached_share_price_raw_u32: 0x42200000,
|
||||
chairman_salary_baseline: 24,
|
||||
chairman_salary_current: 30,
|
||||
founding_year: 1831,
|
||||
last_bankruptcy_year: 0,
|
||||
current_issue_calendar_word: 5,
|
||||
prior_issue_calendar_word: 4,
|
||||
city_connection_latch: true,
|
||||
linked_transit_latch: false,
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
|
||||
let summary = RuntimeSummary::from_state(&state);
|
||||
assert_eq!(summary.company_market_state_owner_count, 1);
|
||||
assert_eq!(summary.selected_company_outstanding_shares, Some(20_000));
|
||||
assert_eq!(
|
||||
summary.selected_company_cached_share_price_value_f32_text,
|
||||
Some("40.000000".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
summary.selected_company_mutable_support_scalar_value_f32_text,
|
||||
Some("1.000000".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,11 @@ The highest-value next passes are now:
|
|||
candidates directly from the rehosted parser, including fixed-world chairman slot / role-gate
|
||||
context, the grounded fixed-world issue-`0x37` pair, the separate six-float economic tuning
|
||||
band, derived holdings-at-share-price and cached purchasing-power totals,
|
||||
context, company dword candidate windows, and richer chairman qword cache views
|
||||
context, company dword candidate windows, and richer chairman qword cache views; the current
|
||||
rehosted company-side owner state now also includes a typed market/cache map carrying saved
|
||||
outstanding-shares, support/share-price/cache words, salary lanes, calendar words, and
|
||||
connection latches for each live company, so later finance/stat-family readers can attach to
|
||||
owned runtime data instead of one more guessed save offset
|
||||
- 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
|
||||
instead of guessing another derived leaf field from neighboring raw offsets
|
||||
|
|
|
|||
|
|
@ -69,7 +69,10 @@ Implemented today:
|
|||
the same fixed world payload now exposes the grounded issue-`0x37` pair at `[world+0x29/+0x2d]`
|
||||
and the separate six-float economic tuning band `[world+0x0be2..+0x0bf6]` through save
|
||||
inspection too, but current atlas evidence still keeps that editor-tuning family separate from
|
||||
the company-governance issue lanes;
|
||||
the company-governance issue lanes; the next shared company-side owning state is rehosted now
|
||||
too, because save-native company direct records now project into a typed runtime
|
||||
`company_market_state` cache map carrying outstanding shares, support/share-price/cache words,
|
||||
chairman salary lanes, calendar words, and connection latches for each live company;
|
||||
and `runtime inspect-save-company-chairman <save.gms>` now exposes the remaining raw
|
||||
company/chairman scalar candidates directly from the rehosted parser, including fixed-world
|
||||
chairman slot / role-gate context, company dword candidate windows, richer chairman qword
|
||||
|
|
@ -189,8 +192,11 @@ frontier is no longer anonymous id recovery; it is the remaining recovered-but-n
|
|||
families from the checked-in semantic catalog, especially cargo-price, add-building, and other
|
||||
descriptor clusters that now have explicit shell-owned or evidence-blocked status but not yet a
|
||||
bounded executable landing surface. Raw save reconstruction for company/chairman context is still a
|
||||
later tranche once stronger evidence exists. Richer runtime ownership should still be added only
|
||||
where a later descriptor or condition family needs more than the current event-owned roster.
|
||||
later tranche once stronger evidence exists, but the current project rule is explicit: prefer
|
||||
rehosting shared owner state and reader/setter families first, and only guess at one more leaf
|
||||
field when that richer owning-state path is blocked. Richer runtime ownership should still be added
|
||||
where later descriptor, stat-family, or simulation work needs more than the current event-owned
|
||||
roster.
|
||||
|
||||
## Why This Boundary
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue