Sample placed-structure side-buffer rows

This commit is contained in:
Jan Petykiewicz 2026-04-18 11:53:13 -07:00
commit e43731c0ef
2 changed files with 63 additions and 0 deletions

View file

@ -1800,9 +1800,27 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
pub first_embedded_primary_name: Option<String>,
#[serde(default)]
pub first_embedded_secondary_name: Option<String>,
#[serde(default)]
pub embedded_name_row_samples: Vec<SmpSavePlacedStructureDynamicSideBufferSampleEntry>,
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)]
pub struct SmpRt3105SaveNameTableProbe {
pub profile_family: String,
@ -10699,6 +10717,45 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
else {
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 {
profile_family: profile.profile_family.clone(),
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(),
first_embedded_primary_name: Some(first_embedded_primary_name.clone()),
first_embedded_secondary_name: Some(first_embedded_secondary_name.clone()),
embedded_name_row_samples,
evidence: vec![
"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(),

View file

@ -97,6 +97,11 @@ Working rule:
`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
`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`
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