aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-23 14:47:16 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-23 14:47:16 +0100
commit6dc7f94764bdbb502884bde0641f59f70d0f92b3 (patch)
tree17e5c0ee2c64ca7746635ed0e6b0c194a07578ba
parent61dcbf35e9afb074f63dbfd78f768c871b4de87b (diff)
downloadunity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar
unity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar.bz2
unity-tools-6dc7f94764bdbb502884bde0641f59f70d0f92b3.tar.zst
seperate type parsing
-rw-r--r--src/classes/mesh.rs10
-rw-r--r--src/serialized_file.rs248
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()
+// });