diff options
author | metamuffin <metamuffin@disroot.org> | 2025-03-23 14:47:16 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-03-23 14:47:16 +0100 |
commit | 6dc7f94764bdbb502884bde0641f59f70d0f92b3 (patch) | |
tree | 17e5c0ee2c64ca7746635ed0e6b0c194a07578ba /src | |
parent | 61dcbf35e9afb074f63dbfd78f768c871b4de87b (diff) | |
download | unity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar unity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar.bz2 unity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar.zst |
seperate type parsing
Diffstat (limited to 'src')
-rw-r--r-- | src/classes/mesh.rs | 10 | ||||
-rw-r--r-- | src/serialized_file.rs | 248 |
2 files changed, 148 insertions, 110 deletions
diff --git a/src/classes/mesh.rs b/src/classes/mesh.rs index 5a9c229..96e42c2 100644 --- a/src/classes/mesh.rs +++ b/src/classes/mesh.rs @@ -152,13 +152,17 @@ impl VertexData { if channel.dimension == 0 { return None; } + let dim = channel.dimension as usize % 48; let component_offset = channel.offset as usize; let component_size = channel.format.component_size(); let (offset, stride) = self.stream_layout()[channel.stream as usize]; - debug!("reading {ch:?} vertex channel (stride={stride}, offset={offset})"); + debug!( + "reading {ch:?} vertex channel (stride={stride}, offset={offset}, format={:?})", + channel.format + ); let mut out = Vec::new(); for vi in 0..self.vertex_count as usize { - for di in 0..channel.dimension as usize { + for di in 0..dim { let off = offset + vi * stride + component_offset + component_size * di; let e = &self.data[off..]; out.push(match channel.format { @@ -177,7 +181,7 @@ impl VertexData { }) } } - Some((channel.dimension as usize, out)) + Some((dim, out)) } pub fn read_channel_vec<T: VectorType>( &self, diff --git a/src/serialized_file.rs b/src/serialized_file.rs index 3ca32aa..32885d6 100644 --- a/src/serialized_file.rs +++ b/src/serialized_file.rs @@ -151,111 +151,7 @@ impl<T: Read + Seek> SerializedFile<T> { let h = SerializedFileHeader::read(&mut file)?; let e = h.endianness; - let has_type_trees = file.read_u8()? != 0; - let num_types = file.read_u32(e)?; - debug!("has_type_trees={has_type_trees:?}"); - debug!("num_types={num_types}"); - - let mut types = Vec::new(); - - for _ in 0..num_types { - let class_id = file.read_i32(e)?; - let stripped_type = file.read_u8()? != 0; - let script_type_index = file.read_i16(e)?; - let mut script_id = 0; - // TODO reftype - if class_id == 114 { - script_id = file.read_u128_be()?; - } - let _old_hash = file.read_u128_be()?; - - trace!("class_id={class_id}"); - trace!("stripped_type={stripped_type}"); - trace!("script_type_index={script_type_index}"); - trace!("script_id={script_id}"); - - let mut type_deps = Vec::new(); - let mut type_tree = None; - if has_type_trees { - let num_nodes = file.read_u32(e)?; - let size = file.read_u32(e)?; - trace!("tree:num_nodes={num_nodes}"); - trace!("tree:size={size}"); - - let mut node_data = vec![0u8; num_nodes as usize * 32]; - file.read_exact(&mut node_data)?; - let mut node_data = Cursor::new(node_data); - let mut string_data = vec![0u8; size as usize]; - file.read_exact(&mut string_data)?; - - let get_string = |off: u32| { - let data = if off & 0x80000000 != 0 { - let off = off & 0x7fffffff; - if off as usize > COMMON_STRINGS.len() { - warn!("common strings missing index {off:08x}"); - b"<common string missing>" - } else { - &COMMON_STRINGS[off as usize..] - } - } else { - &string_data[off as usize..] - }; - String::from_utf8( - data.iter() - .copied() - .take_while(|e| *e != 0) - .collect::<Vec<u8>>(), - ) - }; - - let mut parents: Vec<TypeTreeNode> = vec![]; - for _ in 0..num_nodes { - let node = TypeTreeNode { - version: node_data.read_u16(e)?, - level: node_data.read_u8()?, - type_flags: node_data.read_u8()?, - type_string: get_string(node_data.read_u32(e)?)?, - name_string: get_string(node_data.read_u32(e)?)?, - byte_size: node_data.read_i32(e)?, - index: node_data.read_i32(e)?, - flags: node_data.read_i32(e)?, - ref_type_hash: node_data.read_u64(e)?, - children: vec![], - }; - if node.level == 0 && !parents.is_empty() { - warn!("unexpected toplevel typetree node"); - parents.clear(); - } - while parents.len() > node.level as usize { - let n = parents.pop().unwrap(); - parents.last_mut().unwrap().children.push(n) - } - parents.push(node); - } - while parents.len() > 1 { - let n = parents.pop().unwrap(); - parents.last_mut().unwrap().children.push(n) - } - type_tree = parents.pop(); - - if h.format >= 21 { - let num_deps = file.read_u32(e)?; - trace!("num_deps={num_deps}"); - for _ in 0..num_deps { - type_deps.push(file.read_u32(e)?); - } - } - } - - types.push(SeralizedType { - class_id, - script_id, - script_type_index, - stripped_type, - type_deps, - type_tree, - }) - } + let types = Self::read_types(&mut file, e, h.format)?; let num_objects = file.read_u32(e)?; debug!("num_objects={num_objects}"); @@ -333,6 +229,61 @@ impl<T: Read + Seek> SerializedFile<T> { }) } + pub fn read_types(mut file: &mut T, e: Endianness, format: u32) -> Result<Vec<SeralizedType>> { + let has_type_trees = file.read_u8()? != 0; + let num_types = file.read_u32(e)?; + debug!("has_type_trees={has_type_trees:?}"); + debug!("num_types={num_types}"); + let mut types = Vec::new(); + for ti in 0..num_types { + trace!("TYPE {ti}"); + let class_id = file.read_i32(e)?; + let stripped_type; + let script_type_index; + if format >= 17 { + stripped_type = file.read_u8()? != 0; + script_type_index = file.read_i16(e)?; + } else { + stripped_type = false; + script_type_index = 0; // TODO; + } + let mut script_id = 0; + // TODO reftype + if class_id < 0 || (class_id == 114 && format >= 17) { + script_id = file.read_u128_be()?; + } + let _old_hash = file.read_u128_be()?; + + trace!("t:class_id={class_id}"); + trace!("t:stripped_type={stripped_type}"); + trace!("t:script_type_index={script_type_index}"); + trace!("t:script_id={script_id}"); + + let mut type_deps = Vec::new(); + let mut type_tree = None; + if has_type_trees { + type_tree = Some(TypeTreeNode::read(&mut file, e, format)?); + if format >= 21 { + let num_deps = file.read_u32(e)?; + trace!("num_deps={num_deps}"); + for _ in 0..num_deps { + type_deps.push(file.read_u32(e)?); + } + } + } + + types.push(SeralizedType { + class_id, + script_id, + script_type_index, + stripped_type, + type_deps, + type_tree, + }) + } + Ok(types) + } + pub fn find_fs_shared_assets(&self, fs: &UnityFS<impl Read + Seek>) -> Option<NodeInfo> { let s = self .ecx @@ -358,17 +309,23 @@ impl<T: Read + Seek> SerializedFile<T> { .ok_or(anyhow!("type tree missing")) } pub fn read_object(&mut self, ob: ObjectInfo) -> Result<Value> { + debug!("reading object of type {}", ob.type_id); self.file.seek(SeekFrom::Start(ob.data_offset))?; //? Duplicated impl from get_object_type_tree because borrow problem let r#type = if ob.type_id < 0 { - unimplemented!() + unimplemented!("{}", ob.type_id) } else { &self.types[ob.type_id as usize] }; let typetree = r#type .type_tree .as_ref() - .ok_or(anyhow!("type tree missing"))?; + // .or_else(|| { + // FALLBACK_TYPES + // .get(ob.type_id as usize) + // .and_then(|n| n.type_tree.as_ref()) + // }) + .ok_or(anyhow!("type tree missing for {}", ob.type_id))?; Value::read(typetree, self.endianness, &self.ecx, &mut self.file) } @@ -381,7 +338,84 @@ impl<T: Read + Seek> SerializedFile<T> { } impl TypeTreeNode { + pub fn read(mut file: impl Read + Seek, e: Endianness, format: u32) -> Result<Self> { + let num_nodes = file.read_u32(e)?; + let size = file.read_u32(e)?; + trace!("t:tree:num_nodes={num_nodes}"); + trace!("t:tree:size={size}"); + + let mut node_data = vec![0u8; num_nodes as usize * if format >= 19 { 32 } else { 24 }]; + file.read_exact(&mut node_data)?; + let mut node_data = Cursor::new(node_data); + let mut string_data = vec![0u8; size as usize]; + file.read_exact(&mut string_data)?; + + let get_string = |off: u32| { + if off == 0xffffffff { + return Ok(String::new()); + } + let data = if off & 0x80000000 != 0 { + let off = off & 0x7fffffff; + if off as usize > COMMON_STRINGS.len() { + warn!("common strings missing index {off:08x}"); + b"<common string missing>" + } else { + &COMMON_STRINGS[off as usize..] + } + } else { + &string_data[off as usize..] + }; + String::from_utf8( + data.iter() + .copied() + .take_while(|e| *e != 0) + .collect::<Vec<u8>>(), + ) + }; + + let mut parents: Vec<TypeTreeNode> = vec![]; + for _ in 0..num_nodes { + let node = TypeTreeNode { + version: node_data.read_u16(e)?, + level: node_data.read_u8()?, + type_flags: node_data.read_u8()?, + type_string: get_string(node_data.read_u32(e)?)?, + name_string: get_string(node_data.read_u32(e)?)?, + byte_size: node_data.read_i32(e)?, + index: node_data.read_i32(e)?, + flags: node_data.read_i32(e)?, + ref_type_hash: if format >= 19 { + node_data.read_u64(e)? + } else { + 0 + }, + children: vec![], + }; + if node.level == 0 && !parents.is_empty() { + warn!("unexpected toplevel typetree node"); + parents.clear(); + } + while parents.len() > node.level as usize { + let n = parents.pop().unwrap(); + parents.last_mut().unwrap().children.push(n) + } + parents.push(node); + } + while parents.len() > 1 { + let n = parents.pop().unwrap(); + parents.last_mut().unwrap().children.push(n) + } + parents.pop().ok_or(anyhow!("empty type tree")) + } pub fn post_align(&self) -> bool { self.flags & 0x4000 != 0 } } + +// static FALLBACK_TYPES: LazyLock<Vec<SeralizedType>> = LazyLock::new(|| { +// debug!("need to load fallback types"); +// let mut file = Cursor::new(include_bytes!("fallback_types.bin")); +// file.read_cstr().unwrap(); +// file.read_u32_be().unwrap(); +// SerializedFile::read_types(&mut file, Endianness::Little, 15).unwrap() +// }); |