Probe fixed-world finance neighborhood
This commit is contained in:
parent
26a7a34ad0
commit
dad9291308
4 changed files with 161 additions and 6 deletions
|
|
@ -43,8 +43,9 @@ surface also now exposes `runtime inspect-save-company-chairman <save.gms>` for
|
||||||
company/chairman scalar candidates, including fixed-world chairman slot / role-gate context,
|
company/chairman scalar candidates, including fixed-world chairman slot / role-gate context,
|
||||||
explicit company dword candidate windows, richer chairman qword cache views, and derived
|
explicit company dword candidate windows, richer chairman qword cache views, and derived
|
||||||
holdings-at-share-price / cached purchasing-power comparisons. The same fixed `0x32c8` world
|
holdings-at-share-price / cached purchasing-power comparisons. The same fixed `0x32c8` world
|
||||||
block is now probed for both the grounded issue-`0x37` pair at `[world+0x29/+0x2d]` and the
|
block is now probed for the grounded issue-`0x37` pair at `[world+0x29/+0x2d]`, one broader
|
||||||
separate six-float economic tuning band, but current atlas evidence still keeps that editor-facing
|
fixed-dword finance neighborhood around the absolute-calendar and issue lanes, 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
|
tuning family distinct from the governance issue lanes behind investor confidence and prime-rate
|
||||||
math. The next shared company-side slice is now rehosted too: save-native company direct records
|
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,
|
flow into a typed company market/cache map on runtime service state, carrying outstanding shares,
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,18 @@ const RT3_SAVE_WORLD_BLOCK_SELECTED_COMPANY_ID_RELATIVE_OFFSET: usize = 0x1d;
|
||||||
const RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET: usize = 0x21;
|
const RT3_SAVE_WORLD_BLOCK_SELECTED_CHAIRMAN_PROFILE_ID_RELATIVE_OFFSET: usize = 0x21;
|
||||||
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET: usize = 0x25;
|
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_MULTIPLIER_RELATIVE_OFFSET: usize = 0x25;
|
||||||
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET: usize = 0x29;
|
const RT3_SAVE_WORLD_BLOCK_ISSUE_0X37_VALUE_RELATIVE_OFFSET: usize = 0x29;
|
||||||
|
const RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS: [(&str, usize); 10] = [
|
||||||
|
("absolute_calendar_counter_candidate_0", 0x11),
|
||||||
|
("absolute_calendar_counter_candidate_1", 0x15),
|
||||||
|
("absolute_calendar_counter_candidate_2", 0x19),
|
||||||
|
("selection_context_candidate_0", 0x1d),
|
||||||
|
("selection_context_candidate_1", 0x21),
|
||||||
|
("issue_0x37_multiplier", 0x25),
|
||||||
|
("issue_0x37_value", 0x29),
|
||||||
|
("issue_neighbor_candidate_0", 0x2d),
|
||||||
|
("issue_neighbor_candidate_1", 0x31),
|
||||||
|
("issue_neighbor_candidate_2", 0x35),
|
||||||
|
];
|
||||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET: usize = 0x83;
|
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_SLOT_SELECTOR_RELATIVE_OFFSET: usize = 0x83;
|
||||||
const RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET: usize = 0xc1;
|
const RT3_SAVE_WORLD_BLOCK_CAMPAIGN_OVERRIDE_FLAG_RELATIVE_OFFSET: usize = 0xc1;
|
||||||
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET: usize = 0x0bbf;
|
const RT3_SAVE_WORLD_BLOCK_CHAIRMAN_ROLE_GATE_RELATIVE_OFFSET: usize = 0x0bbf;
|
||||||
|
|
@ -1512,6 +1524,19 @@ pub struct SmpSaveWorldIssue37Probe {
|
||||||
pub evidence: Vec<String>,
|
pub evidence: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct SmpSaveWorldFinanceNeighborhoodProbe {
|
||||||
|
pub profile_family: String,
|
||||||
|
pub source_kind: String,
|
||||||
|
pub semantic_family: String,
|
||||||
|
pub chunk_tag_offset: usize,
|
||||||
|
pub payload_offset: usize,
|
||||||
|
pub payload_len: usize,
|
||||||
|
pub payload_len_hex: String,
|
||||||
|
pub dword_candidates: Vec<SmpSaveDwordCandidate>,
|
||||||
|
pub evidence: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct SmpSaveTaggedCollectionHeaderProbe {
|
pub struct SmpSaveTaggedCollectionHeaderProbe {
|
||||||
pub profile_family: String,
|
pub profile_family: String,
|
||||||
|
|
@ -2341,6 +2366,8 @@ pub struct SmpSaveCompanyChairmanAnalysisReport {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub world_economic_tuning: Option<SmpSaveWorldEconomicTuningProbe>,
|
pub world_economic_tuning: Option<SmpSaveWorldEconomicTuningProbe>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub world_finance_neighborhood: Option<SmpSaveWorldFinanceNeighborhoodProbe>,
|
||||||
|
#[serde(default)]
|
||||||
pub company_entries: Vec<SmpSaveCompanyRecordAnalysisEntry>,
|
pub company_entries: Vec<SmpSaveCompanyRecordAnalysisEntry>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub chairman_entries: Vec<SmpSaveChairmanRecordAnalysisEntry>,
|
pub chairman_entries: Vec<SmpSaveChairmanRecordAnalysisEntry>,
|
||||||
|
|
@ -2592,6 +2619,7 @@ pub struct SmpInspectionReport {
|
||||||
pub save_world_selection_context_probe: Option<SmpSaveWorldSelectionContextProbe>,
|
pub save_world_selection_context_probe: Option<SmpSaveWorldSelectionContextProbe>,
|
||||||
pub save_world_issue_37_probe: Option<SmpSaveWorldIssue37Probe>,
|
pub save_world_issue_37_probe: Option<SmpSaveWorldIssue37Probe>,
|
||||||
pub save_world_economic_tuning_probe: Option<SmpSaveWorldEconomicTuningProbe>,
|
pub save_world_economic_tuning_probe: Option<SmpSaveWorldEconomicTuningProbe>,
|
||||||
|
pub save_world_finance_neighborhood_probe: Option<SmpSaveWorldFinanceNeighborhoodProbe>,
|
||||||
pub save_company_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
|
pub save_company_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
|
||||||
pub save_chairman_profile_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
|
pub save_chairman_profile_collection_header_probe: Option<SmpSaveTaggedCollectionHeaderProbe>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -2906,6 +2934,7 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
|
||||||
let world_selection_context = selection_probe.map(build_save_world_selection_role_analysis);
|
let world_selection_context = selection_probe.map(build_save_world_selection_role_analysis);
|
||||||
let world_issue_37 = report.save_world_issue_37_probe.clone();
|
let world_issue_37 = report.save_world_issue_37_probe.clone();
|
||||||
let world_economic_tuning = report.save_world_economic_tuning_probe.clone();
|
let world_economic_tuning = report.save_world_economic_tuning_probe.clone();
|
||||||
|
let world_finance_neighborhood = report.save_world_finance_neighborhood_probe.clone();
|
||||||
let company_header_probe = report.save_company_collection_header_probe.as_ref();
|
let company_header_probe = report.save_company_collection_header_probe.as_ref();
|
||||||
let chairman_header_probe = report
|
let chairman_header_probe = report
|
||||||
.save_chairman_profile_collection_header_probe
|
.save_chairman_profile_collection_header_probe
|
||||||
|
|
@ -3128,6 +3157,12 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if world_finance_neighborhood.is_some() {
|
||||||
|
notes.push(
|
||||||
|
"World analysis now also exports one fixed dword finance neighborhood around the grounded issue/calendar lanes, so future issue-0x38/0x39 closure can build on rehosted owner-state candidates instead of ad hoc byte guesses."
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
if !company_entries.is_empty() {
|
if !company_entries.is_empty() {
|
||||||
notes.push(
|
notes.push(
|
||||||
"Company debt is derived from the grounded bond table at [company+0x5b/+0x5f] by summing live principal slots.".to_string(),
|
"Company debt is derived from the grounded bond table at [company+0x5b/+0x5f] by summing live principal slots.".to_string(),
|
||||||
|
|
@ -3165,6 +3200,7 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
|
||||||
world_selection_context,
|
world_selection_context,
|
||||||
world_issue_37,
|
world_issue_37,
|
||||||
world_economic_tuning,
|
world_economic_tuning,
|
||||||
|
world_finance_neighborhood,
|
||||||
company_entries,
|
company_entries,
|
||||||
chairman_entries,
|
chairman_entries,
|
||||||
notes,
|
notes,
|
||||||
|
|
@ -6664,6 +6700,11 @@ fn inspect_bundle_bytes(bytes: &[u8], file_extension_hint: Option<String>) -> Sm
|
||||||
file_extension_hint.as_deref(),
|
file_extension_hint.as_deref(),
|
||||||
container_profile.as_ref(),
|
container_profile.as_ref(),
|
||||||
);
|
);
|
||||||
|
let save_world_finance_neighborhood_probe = parse_save_world_finance_neighborhood_probe(
|
||||||
|
bytes,
|
||||||
|
file_extension_hint.as_deref(),
|
||||||
|
container_profile.as_ref(),
|
||||||
|
);
|
||||||
let save_company_collection_header_probe = parse_save_company_collection_header_probe(
|
let save_company_collection_header_probe = parse_save_company_collection_header_probe(
|
||||||
bytes,
|
bytes,
|
||||||
file_extension_hint.as_deref(),
|
file_extension_hint.as_deref(),
|
||||||
|
|
@ -6835,6 +6876,7 @@ fn inspect_bundle_bytes(bytes: &[u8], file_extension_hint: Option<String>) -> Sm
|
||||||
save_world_selection_context_probe,
|
save_world_selection_context_probe,
|
||||||
save_world_issue_37_probe,
|
save_world_issue_37_probe,
|
||||||
save_world_economic_tuning_probe,
|
save_world_economic_tuning_probe,
|
||||||
|
save_world_finance_neighborhood_probe,
|
||||||
save_company_collection_header_probe,
|
save_company_collection_header_probe,
|
||||||
save_chairman_profile_collection_header_probe,
|
save_chairman_profile_collection_header_probe,
|
||||||
save_company_roster_probe,
|
save_company_roster_probe,
|
||||||
|
|
@ -8436,6 +8478,64 @@ fn parse_save_world_issue_37_probe(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_save_world_finance_neighborhood_probe(
|
||||||
|
bytes: &[u8],
|
||||||
|
file_extension_hint: Option<&str>,
|
||||||
|
container_profile: Option<&SmpContainerProfile>,
|
||||||
|
) -> Option<SmpSaveWorldFinanceNeighborhoodProbe> {
|
||||||
|
if file_extension_hint != Some("gms") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let profile = container_profile?;
|
||||||
|
let supported = matches!(
|
||||||
|
profile.profile_family.as_str(),
|
||||||
|
"rt3-classic-save-container-v1"
|
||||||
|
| "rt3-105-save-container-v1"
|
||||||
|
| "rt3-105-scenario-save-container-v1"
|
||||||
|
| "rt3-105-alt-save-container-v1"
|
||||||
|
);
|
||||||
|
if !supported {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk_tag_offset in find_u32_le_offsets(bytes, RT3_SAVE_WORLD_BLOCK_CHUNK_TAG) {
|
||||||
|
let payload_offset = chunk_tag_offset + 4;
|
||||||
|
let next_chunk_tag_offset = payload_offset.checked_add(RT3_SAVE_WORLD_BLOCK_LEN)?;
|
||||||
|
if read_u32_at(bytes, next_chunk_tag_offset) != Some(RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dword_candidates = RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS
|
||||||
|
.iter()
|
||||||
|
.map(|(label, relative_offset)| {
|
||||||
|
build_save_dword_candidate(bytes, payload_offset, label, *relative_offset)
|
||||||
|
})
|
||||||
|
.collect::<Option<Vec<_>>>()?;
|
||||||
|
|
||||||
|
return Some(SmpSaveWorldFinanceNeighborhoodProbe {
|
||||||
|
profile_family: profile.profile_family.clone(),
|
||||||
|
source_kind: "save-direct-world-block".to_string(),
|
||||||
|
semantic_family: "scenario-save-world-finance-neighborhood".to_string(),
|
||||||
|
chunk_tag_offset,
|
||||||
|
payload_offset,
|
||||||
|
payload_len: RT3_SAVE_WORLD_BLOCK_LEN,
|
||||||
|
payload_len_hex: format!("0x{:x}", RT3_SAVE_WORLD_BLOCK_LEN),
|
||||||
|
dword_candidates,
|
||||||
|
evidence: vec![
|
||||||
|
format!(
|
||||||
|
"chunk tag 0x32c8 at 0x{chunk_tag_offset:x} matches the fixed [world+0x04] save block"
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"next chunk tag 0x32c9 appears at 0x{next_chunk_tag_offset:x}, matching the documented 0x4f2c payload span"
|
||||||
|
),
|
||||||
|
"finance-neighborhood candidates cover the fixed dword strip around the grounded world absolute-calendar, selection-context, and issue-0x37 lanes so broader issue-state closure can build on one rehosted owner surface.".to_string(),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_save_world_economic_tuning_probe(
|
fn parse_save_world_economic_tuning_probe(
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
file_extension_hint: Option<&str>,
|
file_extension_hint: Option<&str>,
|
||||||
|
|
@ -15124,6 +15224,58 @@ mod tests {
|
||||||
assert!((probe.multiplier_lane.value_f32 - 0.06).abs() < f32::EPSILON);
|
assert!((probe.multiplier_lane.value_f32 - 0.06).abs() < f32::EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_save_world_finance_neighborhood_probe_from_fixed_world_block() {
|
||||||
|
let mut bytes = vec![0u8; 0x8000];
|
||||||
|
let chunk_tag_offset = 0x3ceusize;
|
||||||
|
let payload_offset = chunk_tag_offset + 4;
|
||||||
|
bytes[chunk_tag_offset..chunk_tag_offset + 4]
|
||||||
|
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_CHUNK_TAG.to_le_bytes());
|
||||||
|
for (index, (_, relative_offset)) in
|
||||||
|
RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
bytes[payload_offset + *relative_offset..payload_offset + *relative_offset + 4]
|
||||||
|
.copy_from_slice(&((index as u32) + 1).to_le_bytes());
|
||||||
|
}
|
||||||
|
let next_chunk_offset = payload_offset + RT3_SAVE_WORLD_BLOCK_LEN;
|
||||||
|
bytes[next_chunk_offset..next_chunk_offset + 4]
|
||||||
|
.copy_from_slice(&RT3_SAVE_WORLD_BLOCK_NEXT_CHUNK_TAG.to_le_bytes());
|
||||||
|
|
||||||
|
let probe = parse_save_world_finance_neighborhood_probe(
|
||||||
|
&bytes,
|
||||||
|
Some("gms"),
|
||||||
|
Some(&SmpContainerProfile {
|
||||||
|
profile_family: "rt3-105-save-container-v1".to_string(),
|
||||||
|
profile_evidence: vec![],
|
||||||
|
is_known_profile: true,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.expect("world finance neighborhood probe should parse");
|
||||||
|
|
||||||
|
assert_eq!(probe.chunk_tag_offset, chunk_tag_offset);
|
||||||
|
assert_eq!(probe.payload_offset, payload_offset);
|
||||||
|
assert_eq!(
|
||||||
|
probe.dword_candidates.len(),
|
||||||
|
RT3_SAVE_WORLD_BLOCK_FINANCE_NEIGHBORHOOD_CANDIDATE_FIELDS.len()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
probe.dword_candidates[0].label,
|
||||||
|
"absolute_calendar_counter_candidate_0"
|
||||||
|
);
|
||||||
|
assert_eq!(probe.dword_candidates[0].relative_offset_hex, "0x11");
|
||||||
|
assert_eq!(probe.dword_candidates[0].value_i32, 1);
|
||||||
|
assert_eq!(probe.dword_candidates[5].label, "issue_0x37_multiplier");
|
||||||
|
assert_eq!(probe.dword_candidates[5].relative_offset_hex, "0x25");
|
||||||
|
assert_eq!(
|
||||||
|
probe.dword_candidates[9].label,
|
||||||
|
"issue_neighbor_candidate_2"
|
||||||
|
);
|
||||||
|
assert_eq!(probe.dword_candidates[9].relative_offset_hex, "0x35");
|
||||||
|
assert_eq!(probe.dword_candidates[9].value_i32, 10);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn loads_selection_only_company_and_chairman_context_from_save_world_probe() {
|
fn loads_selection_only_company_and_chairman_context_from_save_world_probe() {
|
||||||
let mut report = inspect_smp_bytes(&[]);
|
let mut report = inspect_smp_bytes(&[]);
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,9 @@ The highest-value next passes are now:
|
||||||
defaults until their raw offsets are pinned more strongly; the offline analysis command
|
defaults until their raw offsets are pinned more strongly; the offline analysis command
|
||||||
`runtime inspect-save-company-chairman <save.gms>` now dumps those remaining raw record
|
`runtime inspect-save-company-chairman <save.gms>` now dumps those remaining raw record
|
||||||
candidates directly from the rehosted parser, including fixed-world chairman slot / role-gate
|
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
|
context, the grounded fixed-world issue-`0x37` pair, the fixed-dword world finance
|
||||||
band, derived holdings-at-share-price and cached purchasing-power totals,
|
neighborhood around the absolute-calendar and issue lanes, 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; the current
|
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
|
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
|
outstanding-shares, support/share-price/cache words, salary lanes, calendar words, and
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,9 @@ Implemented today:
|
||||||
from the bond table and raw company track-laying capacity from the record tail are grounded too,
|
from the bond table and raw company track-laying capacity from the record tail are grounded too,
|
||||||
and chairman purchasing power now reuses the strongest nonnegative cached qword total from the
|
and chairman purchasing power now reuses the strongest nonnegative cached qword total from the
|
||||||
`[profile+0x1e9..]` band plus current cash instead of collapsing to plain net worth;
|
`[profile+0x1e9..]` band plus current cash instead of collapsing to plain net worth;
|
||||||
the same fixed world payload now exposes the grounded issue-`0x37` pair at `[world+0x29/+0x2d]`
|
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
|
one broader fixed-dword finance neighborhood around the absolute-calendar and nearby issue
|
||||||
|
lanes, 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
|
inspection too, but current atlas evidence still keeps that editor-tuning family separate from
|
||||||
the company-governance issue lanes; the next shared company-side owning state is rehosted now
|
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
|
too, because save-native company direct records now project into a typed runtime
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue