Sample placed-structure side-buffer rows
This commit is contained in:
parent
a669edcaa8
commit
e43731c0ef
2 changed files with 63 additions and 0 deletions
|
|
@ -1800,9 +1800,27 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
|
||||||
pub first_embedded_primary_name: Option<String>,
|
pub first_embedded_primary_name: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub first_embedded_secondary_name: Option<String>,
|
pub first_embedded_secondary_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub embedded_name_row_samples: Vec<SmpSavePlacedStructureDynamicSideBufferSampleEntry>,
|
||||||
pub evidence: Vec<String>,
|
pub evidence: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct SmpSavePlacedStructureDynamicSideBufferSampleEntry {
|
||||||
|
pub sample_index: usize,
|
||||||
|
pub name_tag_relative_offset: usize,
|
||||||
|
pub prefix_leading_dword: u32,
|
||||||
|
pub prefix_leading_dword_hex: String,
|
||||||
|
pub prefix_trailing_word: u16,
|
||||||
|
pub prefix_trailing_word_hex: String,
|
||||||
|
pub prefix_separator_byte: u8,
|
||||||
|
pub prefix_separator_byte_hex: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub primary_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub secondary_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct SmpRt3105SaveNameTableProbe {
|
pub struct SmpRt3105SaveNameTableProbe {
|
||||||
pub profile_family: String,
|
pub profile_family: String,
|
||||||
|
|
@ -10699,6 +10717,45 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let embedded_name_row_samples = embedded_name_tag_offsets
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(sample_index, name_tag_relative_offset)| {
|
||||||
|
let prefix_payload = records_payload.get(..name_tag_relative_offset)?;
|
||||||
|
if prefix_payload.len() < 7 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let prefix_leading_dword = read_u32_at(prefix_payload, prefix_payload.len() - 7)?;
|
||||||
|
let prefix_trailing_word = read_u16_at(prefix_payload, prefix_payload.len() - 3)?;
|
||||||
|
let prefix_separator_byte = *prefix_payload.last()?;
|
||||||
|
let mut parsed_names = None;
|
||||||
|
for relative_name_offset in [4usize, 6usize] {
|
||||||
|
let Some(name_payload) = records_payload
|
||||||
|
.get(name_tag_relative_offset + relative_name_offset..) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if let Some(names) = parse_save_len_prefixed_ascii_name_pair(name_payload) {
|
||||||
|
parsed_names = Some(names);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let (primary_name, secondary_name) = parsed_names.unwrap_or_default();
|
||||||
|
Some(SmpSavePlacedStructureDynamicSideBufferSampleEntry {
|
||||||
|
sample_index,
|
||||||
|
name_tag_relative_offset,
|
||||||
|
prefix_leading_dword,
|
||||||
|
prefix_leading_dword_hex: format!("0x{prefix_leading_dword:08x}"),
|
||||||
|
prefix_trailing_word,
|
||||||
|
prefix_trailing_word_hex: format!("0x{prefix_trailing_word:04x}"),
|
||||||
|
prefix_separator_byte,
|
||||||
|
prefix_separator_byte_hex: format!("0x{prefix_separator_byte:02x}"),
|
||||||
|
primary_name: (!primary_name.is_empty()).then_some(primary_name),
|
||||||
|
secondary_name: (!secondary_name.is_empty()).then_some(secondary_name),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.take(8)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
return Some(SmpSavePlacedStructureDynamicSideBufferProbe {
|
return Some(SmpSavePlacedStructureDynamicSideBufferProbe {
|
||||||
profile_family: profile.profile_family.clone(),
|
profile_family: profile.profile_family.clone(),
|
||||||
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
|
source_kind: "save-placed-structure-dynamic-side-buffer-records".to_string(),
|
||||||
|
|
@ -10723,6 +10780,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
embedded_name_tag_count: embedded_name_tag_offsets.len(),
|
embedded_name_tag_count: embedded_name_tag_offsets.len(),
|
||||||
first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
|
first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
|
||||||
first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
|
first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
|
||||||
|
embedded_name_row_samples,
|
||||||
evidence: vec![
|
evidence: vec![
|
||||||
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
|
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
|
||||||
"records payload begins with a compact 6-byte prefix plus one separator byte before the first embedded 0x55f1 name row".to_string(),
|
"records payload begins with a compact 6-byte prefix plus one separator byte before the first embedded 0x55f1 name row".to_string(),
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,11 @@ Working rule:
|
||||||
`q.gms` exposes `live_record_count=3865`, prefix `0x0005d368/0x0001/0xff`, and first embedded
|
`q.gms` exposes `live_record_count=3865`, prefix `0x0005d368/0x0001/0xff`, and first embedded
|
||||||
names `TrackCapST_Cap.3dp` / `Infrastructure`; `p.gms` exposes the same structure with
|
names `TrackCapST_Cap.3dp` / `Infrastructure`; `p.gms` exposes the same structure with
|
||||||
`live_record_count=2467`.
|
`live_record_count=2467`.
|
||||||
|
- That same direct `0x38a5` probe now also samples multiple embedded name rows with their
|
||||||
|
preceding compact prefixes, showing that the seam is not a one-off wrapper: grounded `q.gms`
|
||||||
|
samples include repeated `TunnelSTBrick_*` names under `Infrastructure` with compact leading
|
||||||
|
dwords like `0x000055f3` and `0xff0000ff`, so the next pass can target the semantics of those
|
||||||
|
compact prefix patterns instead of hunting the owner seam itself.
|
||||||
- The placed-structure tagged save stream now also exposes repeated `0x55f1/0x55f2/0x55f3`
|
- The placed-structure tagged save stream now also exposes repeated `0x55f1/0x55f2/0x55f3`
|
||||||
triplets with dual name stems, a fixed five-`f32` policy row, and a compact `0x5dc1...0x5dc2`
|
triplets with dual name stems, a fixed five-`f32` policy row, and a compact `0x5dc1...0x5dc2`
|
||||||
footer carrying one raw `u32` payload lane plus one live `i32` status lane, so the remaining
|
footer carrying one raw `u32` payload lane plus one live `i32` status lane, so the remaining
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue