Probe stock building header families
This commit is contained in:
parent
311712b051
commit
6c7ebb75b5
4 changed files with 131 additions and 0 deletions
|
|
@ -21,6 +21,8 @@ pub struct BuildingTypeSourceFile {
|
|||
pub byte_len: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub bca_selector_probe: Option<BuildingTypeBcaSelectorProbe>,
|
||||
#[serde(default)]
|
||||
pub bty_header_probe: Option<BuildingTypeBtyHeaderProbe>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -43,6 +45,26 @@ pub struct BuildingTypeBcaSelectorProbe {
|
|||
pub byte_0xbb_hex: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BuildingTypeBtyHeaderProbe {
|
||||
pub type_id: u32,
|
||||
pub type_id_hex: String,
|
||||
pub name_0x04: String,
|
||||
pub name_0x22: String,
|
||||
pub name_0x40: String,
|
||||
pub name_0x5e: String,
|
||||
pub name_0x7c: String,
|
||||
pub name_0x9a: String,
|
||||
pub byte_0xb8: u8,
|
||||
pub byte_0xb8_hex: String,
|
||||
pub byte_0xb9: u8,
|
||||
pub byte_0xb9_hex: String,
|
||||
pub byte_0xba: u8,
|
||||
pub byte_0xba_hex: String,
|
||||
pub dword_0xbb: u32,
|
||||
pub dword_0xbb_hex: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BuildingTypeBcaSelectorPatternSummary {
|
||||
pub byte_len: usize,
|
||||
|
|
@ -136,6 +158,10 @@ pub fn inspect_building_types_dir_with_bindings(
|
|||
BuildingTypeSourceKind::Bca => Some(probe_bca_selector_bytes(&bytes)),
|
||||
BuildingTypeSourceKind::Bty => None,
|
||||
},
|
||||
bty_header_probe: match source_kind {
|
||||
BuildingTypeSourceKind::Bca => None,
|
||||
BuildingTypeSourceKind::Bty => Some(probe_bty_header(&bytes)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -267,6 +293,47 @@ fn probe_bca_selector_bytes(bytes: &[u8]) -> BuildingTypeBcaSelectorProbe {
|
|||
}
|
||||
}
|
||||
|
||||
fn probe_bty_header(bytes: &[u8]) -> BuildingTypeBtyHeaderProbe {
|
||||
let type_id = read_u32_le(bytes, 0x00);
|
||||
let byte_0xb8 = bytes.get(0xb8).copied().unwrap_or(0);
|
||||
let byte_0xb9 = bytes.get(0xb9).copied().unwrap_or(0);
|
||||
let byte_0xba = bytes.get(0xba).copied().unwrap_or(0);
|
||||
let dword_0xbb = read_u32_le(bytes, 0xbb);
|
||||
BuildingTypeBtyHeaderProbe {
|
||||
type_id,
|
||||
type_id_hex: format!("0x{type_id:08x}"),
|
||||
name_0x04: read_c_string(bytes, 0x04, 0x1e),
|
||||
name_0x22: read_c_string(bytes, 0x22, 0x1e),
|
||||
name_0x40: read_c_string(bytes, 0x40, 0x1e),
|
||||
name_0x5e: read_c_string(bytes, 0x5e, 0x1e),
|
||||
name_0x7c: read_c_string(bytes, 0x7c, 0x1e),
|
||||
name_0x9a: read_c_string(bytes, 0x9a, 0x1e),
|
||||
byte_0xb8,
|
||||
byte_0xb8_hex: format!("0x{byte_0xb8:02x}"),
|
||||
byte_0xb9,
|
||||
byte_0xb9_hex: format!("0x{byte_0xb9:02x}"),
|
||||
byte_0xba,
|
||||
byte_0xba_hex: format!("0x{byte_0xba:02x}"),
|
||||
dword_0xbb,
|
||||
dword_0xbb_hex: format!("0x{dword_0xbb:08x}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u32_le(bytes: &[u8], offset: usize) -> u32 {
|
||||
bytes.get(offset..offset + 4)
|
||||
.and_then(|slice| <[u8; 4]>::try_from(slice).ok())
|
||||
.map(u32::from_le_bytes)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn read_c_string(bytes: &[u8], offset: usize, max_len: usize) -> String {
|
||||
let Some(slice) = bytes.get(offset..offset.saturating_add(max_len)) else {
|
||||
return String::new();
|
||||
};
|
||||
let end = slice.iter().position(|byte| *byte == 0).unwrap_or(slice.len());
|
||||
String::from_utf8_lossy(&slice[..end]).into_owned()
|
||||
}
|
||||
|
||||
fn load_named_binding_comparison(
|
||||
bindings_path: &Path,
|
||||
entries: &[BuildingTypeSourceEntry],
|
||||
|
|
@ -416,6 +483,36 @@ mod tests {
|
|||
assert_eq!(probe.byte_0xbb_hex, "0x78");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probes_bty_header_from_fixed_offsets() {
|
||||
let mut bytes = vec![0u8; 0xc0];
|
||||
bytes[0x00..0x04].copy_from_slice(&0x03ebu32.to_le_bytes());
|
||||
bytes[0x04..0x04 + 5].copy_from_slice(b"Port\0");
|
||||
bytes[0x22..0x22 + 7].copy_from_slice(b"Cargo\0\0");
|
||||
bytes[0x40..0x40 + 6].copy_from_slice(b"Dock\0\0");
|
||||
bytes[0x5e..0x5e + 5].copy_from_slice(b"Sea\0\0");
|
||||
bytes[0x7c..0x7c + 6].copy_from_slice(b"Coast\0");
|
||||
bytes[0x9a..0x9a + 5].copy_from_slice(b"Port\0");
|
||||
bytes[0xb8] = 0x12;
|
||||
bytes[0xb9] = 0x34;
|
||||
bytes[0xba] = 0x56;
|
||||
bytes[0xbb..0xbf].copy_from_slice(&0x89abcdefu32.to_le_bytes());
|
||||
|
||||
let probe = probe_bty_header(&bytes);
|
||||
assert_eq!(probe.type_id, 0x03eb);
|
||||
assert_eq!(probe.type_id_hex, "0x000003eb");
|
||||
assert_eq!(probe.name_0x04, "Port");
|
||||
assert_eq!(probe.name_0x22, "Cargo");
|
||||
assert_eq!(probe.name_0x40, "Dock");
|
||||
assert_eq!(probe.name_0x5e, "Sea");
|
||||
assert_eq!(probe.name_0x7c, "Coast");
|
||||
assert_eq!(probe.name_0x9a, "Port");
|
||||
assert_eq!(probe.byte_0xb8_hex, "0x12");
|
||||
assert_eq!(probe.byte_0xb9_hex, "0x34");
|
||||
assert_eq!(probe.byte_0xba_hex, "0x56");
|
||||
assert_eq!(probe.dword_0xbb_hex, "0x89abcdef");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarizes_recovered_table_families_from_entries_and_files() {
|
||||
let entries = vec![
|
||||
|
|
@ -452,6 +549,7 @@ mod tests {
|
|||
source_kind: BuildingTypeSourceKind::Bty,
|
||||
byte_len: None,
|
||||
bca_selector_probe: None,
|
||||
bty_header_probe: None,
|
||||
},
|
||||
BuildingTypeSourceFile {
|
||||
file_name: "Warehouse.bca".to_string(),
|
||||
|
|
@ -460,6 +558,7 @@ mod tests {
|
|||
source_kind: BuildingTypeSourceKind::Bca,
|
||||
byte_len: None,
|
||||
bca_selector_probe: None,
|
||||
bty_header_probe: None,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue