Rehost saved company year stat families
This commit is contained in:
parent
5ea2ce58b4
commit
cbf0dbeda5
5 changed files with 366 additions and 13 deletions
|
|
@ -5148,6 +5148,8 @@ mod tests {
|
|||
stat_band_root_0cfb_candidates: Vec::new(),
|
||||
stat_band_root_0d7f_candidates: Vec::new(),
|
||||
stat_band_root_1c47_candidates: Vec::new(),
|
||||
year_stat_family_qword_bits: Vec::new(),
|
||||
special_stat_family_232a_qword_bits: Vec::new(),
|
||||
}),
|
||||
},
|
||||
crate::SmpLoadedCompanyRosterEntry {
|
||||
|
|
@ -5199,6 +5201,8 @@ mod tests {
|
|||
stat_band_root_0cfb_candidates: Vec::new(),
|
||||
stat_band_root_0d7f_candidates: Vec::new(),
|
||||
stat_band_root_1c47_candidates: Vec::new(),
|
||||
year_stat_family_qword_bits: Vec::new(),
|
||||
special_stat_family_232a_qword_bits: Vec::new(),
|
||||
}),
|
||||
},
|
||||
],
|
||||
|
|
@ -6583,6 +6587,8 @@ mod tests {
|
|||
stat_band_root_0cfb_candidates: Vec::new(),
|
||||
stat_band_root_0d7f_candidates: Vec::new(),
|
||||
stat_band_root_1c47_candidates: Vec::new(),
|
||||
year_stat_family_qword_bits: Vec::new(),
|
||||
special_stat_family_232a_qword_bits: Vec::new(),
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
|
|
|
|||
|
|
@ -44,10 +44,11 @@ pub use pk4::{
|
|||
extract_pk4_entry_bytes, extract_pk4_entry_file, inspect_pk4_bytes, inspect_pk4_file,
|
||||
};
|
||||
pub use runtime::{
|
||||
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER, RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE,
|
||||
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH, RUNTIME_WORLD_ISSUE_CREDIT_MARKET,
|
||||
RUNTIME_WORLD_ISSUE_INVESTOR_CONFIDENCE, RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE,
|
||||
RUNTIME_WORLD_ISSUE_PRIME_RATE,
|
||||
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER, RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A,
|
||||
RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE, RUNTIME_COMPANY_STAT_SLOT_COUNT,
|
||||
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH, RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN,
|
||||
RUNTIME_WORLD_ISSUE_CREDIT_MARKET, RUNTIME_WORLD_ISSUE_INVESTOR_CONFIDENCE,
|
||||
RUNTIME_WORLD_ISSUE_MANAGEMENT_ATTITUDE, RUNTIME_WORLD_ISSUE_PRIME_RATE,
|
||||
RuntimeCargoCatalogEntry, RuntimeCargoClass, RuntimeCargoPriceTarget,
|
||||
RuntimeCargoProductionTarget, RuntimeChairmanMetric, RuntimeChairmanProfile,
|
||||
RuntimeChairmanTarget, RuntimeCompany, RuntimeCompanyAnnualFinanceState,
|
||||
|
|
@ -65,7 +66,8 @@ pub use runtime::{
|
|||
RuntimeTrackPieceCounts, RuntimeTrain, RuntimeWorldFinanceNeighborhoodCandidate,
|
||||
RuntimeWorldIssueState, RuntimeWorldRestoreState, runtime_company_annual_finance_state,
|
||||
runtime_company_assigned_share_pool, runtime_company_market_value, runtime_company_stat_value,
|
||||
runtime_company_unassigned_share_pool, runtime_world_issue_state,
|
||||
runtime_company_stat_value_f64, runtime_company_unassigned_share_pool,
|
||||
runtime_world_issue_state,
|
||||
};
|
||||
pub use smp::{
|
||||
SMP_FOUR_SIDECAR_BYTE_PLANES_MIN_BUNDLE_VERSION, SmpAlignedRuntimeRuleBandLane,
|
||||
|
|
|
|||
|
|
@ -100,6 +100,10 @@ pub struct RuntimeCompanyMarketState {
|
|||
pub stat_band_root_0d7f_candidates: Vec<RuntimeCompanyStatBandCandidate>,
|
||||
#[serde(default)]
|
||||
pub stat_band_root_1c47_candidates: Vec<RuntimeCompanyStatBandCandidate>,
|
||||
#[serde(default)]
|
||||
pub year_stat_family_qword_bits: Vec<u64>,
|
||||
#[serde(default)]
|
||||
pub special_stat_family_232a_qword_bits: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -413,8 +417,11 @@ pub struct RuntimeCompanyStatSelector {
|
|||
}
|
||||
|
||||
pub const RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER: u32 = 0x2329;
|
||||
pub const RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A: u32 = 0x232a;
|
||||
pub const RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH: u32 = 0x0d;
|
||||
pub const RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE: u32 = 0x1d;
|
||||
pub const RUNTIME_COMPANY_STAT_SLOT_COUNT: u32 = 0x2b;
|
||||
pub const RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN: u32 = 11;
|
||||
pub const RUNTIME_WORLD_ISSUE_INVESTOR_CONFIDENCE: u32 = 0x37;
|
||||
pub const RUNTIME_WORLD_ISSUE_CREDIT_MARKET: u32 = 0x38;
|
||||
pub const RUNTIME_WORLD_ISSUE_PRIME_RATE: u32 = 0x39;
|
||||
|
|
@ -1920,22 +1927,133 @@ pub fn runtime_company_stat_value(
|
|||
company_id: u32,
|
||||
selector: RuntimeCompanyStatSelector,
|
||||
) -> Option<i64> {
|
||||
runtime_company_stat_value_f64(state, company_id, selector).and_then(runtime_round_f64_to_i64)
|
||||
}
|
||||
|
||||
pub fn runtime_company_stat_value_f64(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
selector: RuntimeCompanyStatSelector,
|
||||
) -> Option<f64> {
|
||||
if selector.slot_id >= RUNTIME_COMPANY_STAT_SLOT_COUNT {
|
||||
return runtime_company_derived_stat_value_f64(
|
||||
state,
|
||||
company_id,
|
||||
selector.family_id,
|
||||
selector.slot_id,
|
||||
);
|
||||
}
|
||||
match selector.family_id {
|
||||
RUNTIME_COMPANY_STAT_FAMILY_CONTROL_TRANSFER => {
|
||||
runtime_company_control_transfer_stat_value_f64(state, company_id, selector.slot_id)
|
||||
}
|
||||
RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A => {
|
||||
runtime_company_special_stat_family_232a_value_f64(state, company_id, selector.slot_id)
|
||||
}
|
||||
family_id => runtime_company_year_stat_value_f64(state, company_id, family_id, selector.slot_id),
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_company_control_transfer_stat_value_f64(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
slot_id: u32,
|
||||
) -> Option<f64> {
|
||||
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),
|
||||
match slot_id {
|
||||
RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH => Some(company.current_cash as f64),
|
||||
RUNTIME_COMPANY_STAT_SLOT_BOOK_VALUE_PER_SHARE => Some(company.book_value_per_share as f64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_company_special_stat_family_232a_value_f64(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
slot_id: u32,
|
||||
) -> Option<f64> {
|
||||
let market_state = state.service_state.company_market_state.get(&company_id)?;
|
||||
let value = runtime_decode_saved_f64_bits(
|
||||
*market_state
|
||||
.special_stat_family_232a_qword_bits
|
||||
.get(slot_id as usize)?,
|
||||
)?;
|
||||
if (0x13..=0x1b).contains(&slot_id) {
|
||||
Some(value + runtime_company_control_transfer_stat_value_f64(state, company_id, slot_id)?)
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_company_year_stat_value_f64(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
family_id: u32,
|
||||
slot_id: u32,
|
||||
) -> Option<f64> {
|
||||
let current_year_word = u32::from(state.world_restore.packed_year_word_raw_u16?);
|
||||
let year_delta = current_year_word.checked_sub(family_id)?;
|
||||
if year_delta == 0 || year_delta >= RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN {
|
||||
return None;
|
||||
}
|
||||
let market_state = state.service_state.company_market_state.get(&company_id)?;
|
||||
let index = slot_id
|
||||
.checked_mul(RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN)?
|
||||
.checked_add(year_delta)? as usize;
|
||||
runtime_decode_saved_f64_bits(*market_state.year_stat_family_qword_bits.get(index)?)
|
||||
}
|
||||
|
||||
fn runtime_company_derived_stat_value_f64(
|
||||
state: &RuntimeState,
|
||||
company_id: u32,
|
||||
family_id: u32,
|
||||
slot_id: u32,
|
||||
) -> Option<f64> {
|
||||
let stat = |slot_id| {
|
||||
runtime_company_stat_value_f64(
|
||||
state,
|
||||
company_id,
|
||||
RuntimeCompanyStatSelector { family_id, slot_id },
|
||||
)
|
||||
};
|
||||
let rounded_stat = |slot_id| stat(slot_id).and_then(runtime_round_f64_to_i64);
|
||||
match slot_id {
|
||||
0x2b => Some(stat(0x2d)? + stat(0x2c)?),
|
||||
0x2c => Some(stat(0x04)? + stat(0x03)? + stat(0x02)? + stat(0x01)?),
|
||||
0x2d => Some(stat(0x2f)? + stat(0x2e)?),
|
||||
0x2e => Some(
|
||||
stat(0x0c)?
|
||||
+ stat(0x0b)?
|
||||
+ stat(0x0a)?
|
||||
+ stat(0x08)?
|
||||
+ stat(0x07)?
|
||||
+ stat(0x06)?
|
||||
+ stat(0x05)?,
|
||||
),
|
||||
0x2f => stat(0x09),
|
||||
0x30 => Some(stat(0x11)? + stat(0x10)? + stat(0x0f)? + stat(0x0e)? + stat(0x0d)?),
|
||||
0x31 => Some(stat(0x30)? + stat(0x12)?),
|
||||
0x32 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x24)?),
|
||||
0x33 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x16)?),
|
||||
0x34 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x17)?),
|
||||
0x35 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x18)?),
|
||||
0x36 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x19)?),
|
||||
0x37 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x1a)?),
|
||||
0x38 => runtime_divide_by_rounded_stat_i64(stat(0x2c)?, rounded_stat(0x1b)?),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_divide_by_rounded_stat_i64(numerator: f64, denominator: i64) -> Option<f64> {
|
||||
if denominator == 0 {
|
||||
return Some(0.0);
|
||||
}
|
||||
Some(numerator / denominator as f64)
|
||||
}
|
||||
|
||||
pub fn runtime_world_issue_state(
|
||||
state: &RuntimeState,
|
||||
issue_id: u32,
|
||||
|
|
@ -2178,6 +2296,24 @@ fn rounded_cached_share_price_i64(raw_u32: u32) -> Option<i64> {
|
|||
Some(value.round() as i64)
|
||||
}
|
||||
|
||||
fn runtime_decode_saved_f64_bits(bits: u64) -> Option<f64> {
|
||||
let value = f64::from_bits(bits);
|
||||
if !value.is_finite() {
|
||||
return None;
|
||||
}
|
||||
Some(value)
|
||||
}
|
||||
|
||||
fn runtime_round_f64_to_i64(value: f64) -> Option<i64> {
|
||||
if !value.is_finite() {
|
||||
return None;
|
||||
}
|
||||
if value < i64::MIN as f64 || value > i64::MAX as f64 {
|
||||
return None;
|
||||
}
|
||||
Some(value.round() as i64)
|
||||
}
|
||||
|
||||
fn derive_runtime_company_elapsed_years(current_year: u32, prior_year: u32) -> Option<u32> {
|
||||
if prior_year == 0 || prior_year > current_year {
|
||||
return None;
|
||||
|
|
@ -4175,6 +4311,180 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_year_relative_company_stat_family_from_saved_market_matrix() {
|
||||
let mut year_stat_family_qword_bits =
|
||||
vec![0u64; (RUNTIME_COMPANY_STAT_SLOT_COUNT * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN) as usize];
|
||||
let write_year_value = |bits: &mut Vec<u64>, slot_id: u32, year_delta: u32, value: f64| {
|
||||
let index = (slot_id * RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN + year_delta) as usize;
|
||||
bits[index] = value.to_bits();
|
||||
};
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x01, 1, 10.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x02, 1, 20.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x03, 1, 30.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x04, 1, 40.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x05, 1, 5.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x06, 1, 6.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x07, 1, 7.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x08, 1, 8.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x09, 1, 9.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0a, 1, 10.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0b, 1, 11.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0c, 1, 12.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0d, 1, 13.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0e, 1, 14.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x0f, 1, 15.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x10, 1, 16.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x11, 1, 17.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x12, 1, 18.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x16, 1, 4.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x17, 1, 10.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x18, 1, 20.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x19, 1, 25.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x1a, 1, 50.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x1b, 1, 100.0);
|
||||
write_year_value(&mut year_stat_family_qword_bits, 0x24, 1, 5.0);
|
||||
|
||||
let mut special_stat_family_232a_qword_bits =
|
||||
vec![0u64; RUNTIME_COMPANY_STAT_SLOT_COUNT as usize];
|
||||
special_stat_family_232a_qword_bits[RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH as usize] =
|
||||
111.0f64.to_bits();
|
||||
|
||||
let state = RuntimeState {
|
||||
calendar: CalendarPoint {
|
||||
year: 1845,
|
||||
month_slot: 0,
|
||||
phase_slot: 0,
|
||||
tick_slot: 0,
|
||||
},
|
||||
world_flags: BTreeMap::new(),
|
||||
save_profile: RuntimeSaveProfileState::default(),
|
||||
world_restore: RuntimeWorldRestoreState {
|
||||
packed_year_word_raw_u16: Some(1845),
|
||||
..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 {
|
||||
company_market_state: BTreeMap::from([(
|
||||
7,
|
||||
RuntimeCompanyMarketState {
|
||||
year_stat_family_qword_bits,
|
||||
special_stat_family_232a_qword_bits,
|
||||
..RuntimeCompanyMarketState::default()
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
},
|
||||
};
|
||||
|
||||
let prior_year = RuntimeCompanyStatSelector {
|
||||
family_id: 1844,
|
||||
slot_id: 0x09,
|
||||
};
|
||||
assert_eq!(runtime_company_stat_value_f64(&state, 7, prior_year), Some(9.0));
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
7,
|
||||
RuntimeCompanyStatSelector {
|
||||
family_id: 1844,
|
||||
slot_id: 0x2c,
|
||||
},
|
||||
),
|
||||
Some(100.0)
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
7,
|
||||
RuntimeCompanyStatSelector {
|
||||
family_id: 1844,
|
||||
slot_id: 0x2b,
|
||||
},
|
||||
),
|
||||
Some(168.0)
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
7,
|
||||
RuntimeCompanyStatSelector {
|
||||
family_id: 1844,
|
||||
slot_id: 0x32,
|
||||
},
|
||||
),
|
||||
Some(20.0)
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
7,
|
||||
RuntimeCompanyStatSelector {
|
||||
family_id: 1844,
|
||||
slot_id: 0x38,
|
||||
},
|
||||
),
|
||||
Some(1.0)
|
||||
);
|
||||
assert_eq!(
|
||||
runtime_company_stat_value_f64(
|
||||
&state,
|
||||
7,
|
||||
RuntimeCompanyStatSelector {
|
||||
family_id: RUNTIME_COMPANY_STAT_FAMILY_SPECIAL_232A,
|
||||
slot_id: RUNTIME_COMPANY_STAT_SLOT_CURRENT_CASH,
|
||||
},
|
||||
),
|
||||
Some(111.0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_grounded_world_issue_state_from_runtime_restore_state() {
|
||||
let state = RuntimeState {
|
||||
|
|
|
|||
|
|
@ -3588,6 +3588,11 @@ const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0CFB_OFFSET: usize = 0x0cfb;
|
|||
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET: usize = 0x0d7f;
|
||||
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET: usize = 0x1c47;
|
||||
const SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS: usize = 32;
|
||||
const SAVE_COMPANY_RECORD_YEAR_STAT_FAMILY_QWORD_COUNT: usize =
|
||||
crate::runtime::RUNTIME_COMPANY_STAT_SLOT_COUNT as usize
|
||||
* crate::runtime::RUNTIME_COMPANY_YEAR_STAT_FAMILY_SPAN as usize;
|
||||
const SAVE_COMPANY_RECORD_SPECIAL_STAT_FAMILY_232A_QWORD_COUNT: usize =
|
||||
crate::runtime::RUNTIME_COMPANY_STAT_SLOT_COUNT as usize;
|
||||
const SAVE_COMPANY_RECORD_SCALAR_CANDIDATE_FIELDS: [(&str, usize); 9] = [
|
||||
("mutable_support_scalar", 0x4f),
|
||||
("young_company_support_scalar", 0x57),
|
||||
|
|
@ -3784,6 +3789,18 @@ fn parse_save_company_roster_probe(
|
|||
"stat_band_1c47",
|
||||
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_WINDOW_LEN_DWORDS,
|
||||
)?;
|
||||
let year_stat_family_qword_bits = build_save_company_stat_qword_bits(
|
||||
bytes,
|
||||
record_offset,
|
||||
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_0D7F_OFFSET,
|
||||
SAVE_COMPANY_RECORD_YEAR_STAT_FAMILY_QWORD_COUNT,
|
||||
)?;
|
||||
let special_stat_family_232a_qword_bits = build_save_company_stat_qword_bits(
|
||||
bytes,
|
||||
record_offset,
|
||||
SAVE_COMPANY_RECORD_STAT_BAND_ROOT_1C47_OFFSET,
|
||||
SAVE_COMPANY_RECORD_SPECIAL_STAT_FAMILY_232A_QWORD_COUNT,
|
||||
)?;
|
||||
entries.push(SmpLoadedCompanyRosterEntry {
|
||||
company_id,
|
||||
active,
|
||||
|
|
@ -3835,6 +3852,8 @@ fn parse_save_company_roster_probe(
|
|||
.iter()
|
||||
.map(runtime_company_stat_band_candidate_from_save)
|
||||
.collect(),
|
||||
year_stat_family_qword_bits,
|
||||
special_stat_family_232a_qword_bits,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
@ -3878,6 +3897,20 @@ fn build_save_company_stat_band_candidates(
|
|||
.collect::<Option<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn build_save_company_stat_qword_bits(
|
||||
bytes: &[u8],
|
||||
record_offset: usize,
|
||||
root_offset: usize,
|
||||
qword_count: usize,
|
||||
) -> Option<Vec<u64>> {
|
||||
(0..qword_count)
|
||||
.map(|index| {
|
||||
let relative_offset = root_offset.checked_add(index.checked_mul(8)?)?;
|
||||
read_u64_at(bytes, record_offset + relative_offset)
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn detect_save_company_record_start_offset(
|
||||
bytes: &[u8],
|
||||
header_probe: &SmpSaveTaggedCollectionHeaderProbe,
|
||||
|
|
|
|||
|
|
@ -2102,6 +2102,8 @@ mod tests {
|
|||
value_f32_text: "0.000000".to_string(),
|
||||
},
|
||||
],
|
||||
year_stat_family_qword_bits: Vec::new(),
|
||||
special_stat_family_232a_qword_bits: Vec::new(),
|
||||
},
|
||||
)]),
|
||||
..RuntimeServiceState::default()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue