From 2ee2f1af847dbc9f1292baefc9fd652167b9103a Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sat, 22 Mar 2025 17:18:39 +0100 Subject: relative file ids --- exporter/src/bin/debug.rs | 4 +-- exporter/src/bin/json.rs | 2 +- exporter/src/bin/typegraph.rs | 2 +- exporter/src/bin/yaml.rs | 2 +- src/assetbundle.rs | 14 +++++----- src/classes/pptr.rs | 60 +++++++++++++++++++++++++------------------ src/classes/streaminginfo.rs | 5 +++- src/object/helper.rs | 2 +- src/object/mod.rs | 1 + src/object/parser.rs | 2 +- src/object/read.rs | 16 ++++++++---- src/serialized_file.rs | 11 ++++++-- 12 files changed, 75 insertions(+), 46 deletions(-) diff --git a/exporter/src/bin/debug.rs b/exporter/src/bin/debug.rs index 3f87ccf..b1d8d12 100644 --- a/exporter/src/bin/debug.rs +++ b/exporter/src/bin/debug.rs @@ -8,9 +8,9 @@ fn main() -> anyhow::Result<()> { let node = fs.find_main_file().unwrap().to_owned(); let mut cab = fs.read(&node)?; - let file = SerializedFile::read(&mut cab)?; + let file = SerializedFile::read(&mut cab, 0)?; let shared_assets = if let Some(n) = file.find_fs_shared_assets(&fs) { - Some(SerializedFile::read(fs.read(&n)?)?) + Some(SerializedFile::read(fs.read(&n)?, 1)?) } else { None }; diff --git a/exporter/src/bin/json.rs b/exporter/src/bin/json.rs index e03642b..57a0edc 100644 --- a/exporter/src/bin/json.rs +++ b/exporter/src/bin/json.rs @@ -14,7 +14,7 @@ fn main() -> anyhow::Result<()> { let node = fs.find_main_file().unwrap().to_owned(); let mut cab = fs.read(&node)?; - let mut file = SerializedFile::read(&mut cab)?; + let mut file = SerializedFile::read(&mut cab, 0)?; for ob in file.objects.clone() { if let Some(f) = &filter { if file.get_object_type_tree(&ob)?.type_string != *f && ob.path_id.to_string() != *f { diff --git a/exporter/src/bin/typegraph.rs b/exporter/src/bin/typegraph.rs index 0d6568a..388f36f 100644 --- a/exporter/src/bin/typegraph.rs +++ b/exporter/src/bin/typegraph.rs @@ -19,7 +19,7 @@ fn main() -> anyhow::Result<()> { let mut edges = BTreeSet::new(); let node = fs.find_main_file().unwrap().to_owned(); let mut cab = fs.read(&node)?; - let file = SerializedFile::read(&mut cab)?; + let file = SerializedFile::read(&mut cab, 0)?; for ob in file.objects { let typetree = if ob.type_id < 0 { diff --git a/exporter/src/bin/yaml.rs b/exporter/src/bin/yaml.rs index bc9e57e..26cd04b 100644 --- a/exporter/src/bin/yaml.rs +++ b/exporter/src/bin/yaml.rs @@ -15,7 +15,7 @@ fn main() -> anyhow::Result<()> { let node = fs.find_main_file().unwrap().to_owned(); let mut cab = fs.read(&node)?; - let mut file = SerializedFile::read(&mut cab)?; + let mut file = SerializedFile::read(&mut cab,0)?; for ob in file.objects.clone() { if let Some(f) = &filter { if file.get_object_type_tree(&ob)?.type_string != *f && ob.path_id.to_string() != *f { diff --git a/src/assetbundle.rs b/src/assetbundle.rs index db7ad97..8f6af15 100644 --- a/src/assetbundle.rs +++ b/src/assetbundle.rs @@ -24,10 +24,10 @@ impl AssetBundle { .find_main_file() .ok_or(anyhow!("AssetBundle seems to lack main file"))?; debug!("detected {:?} as main file", main_ni.name); - let main = SerializedFile::read(fs.read(main_ni)?)?; + let main = SerializedFile::read(fs.read(main_ni)?, 0)?; let shared_assets = if let Some(n) = main.find_fs_shared_assets(&fs) { debug!("detect {:?} as shared assets", n.name); - Some(SerializedFile::read(fs.read(&n)?)?) + Some(SerializedFile::read(fs.read(&n)?, 1)?) } else { None }; @@ -50,9 +50,10 @@ impl AssetBundle { .into_iter() .flatten(), ) - .map(|(fi, o)| PPtr { + .map(|(si, o)| PPtr { class: "".to_string(), - file_id: fi, + source_file: si, + file_id: 0, path_id: o.path_id, _class: PhantomData, }) @@ -69,9 +70,10 @@ impl AssetBundle { .into_iter() .flatten(), ) - .map(|(fi, o)| PPtr { + .map(|(si, o)| PPtr { class: class_name.to_owned(), - file_id: fi, + source_file: si, + file_id: 0, path_id: o.path_id, _class: PhantomData, }) diff --git a/src/classes/pptr.rs b/src/classes/pptr.rs index 366e17c..0e66b5f 100644 --- a/src/classes/pptr.rs +++ b/src/classes/pptr.rs @@ -15,13 +15,19 @@ pub struct PPtr { #[serde(skip, default)] pub(crate) _class: PhantomData, pub class: String, + pub source_file: usize, pub file_id: i32, pub path_id: i64, } impl FromValue for PPtr { fn from_value(v: Value) -> Result { - let Value::Object { class, fields } = v else { + let Value::Object { + class, + fields, + file, + } = v + else { bail!("PPtr expected but not an object") }; let inner = class @@ -32,6 +38,7 @@ impl FromValue for PPtr { Ok(PPtr { class: inner.to_owned(), _class: PhantomData, + source_file: file, file_id: fields["m_FileID"] .as_i32() .ok_or(anyhow!("PPtr m_FileID is not i32"))?, @@ -47,6 +54,7 @@ impl PPtr { PPtr { _class: PhantomData, class: self.class, + source_file: self.source_file, file_id: self.file_id, path_id: self.path_id, } @@ -59,30 +67,32 @@ impl PPtr { "loading PPtr<{}> file_id={} path_id={}", self.class, self.file_id, self.path_id ); - match self.file_id { - 0 => { - let ob = bundle - .main - .objects - .iter() - .find(|o| o.path_id == self.path_id) - .ok_or(anyhow!("object with path id {} not found", self.path_id))? - .to_owned(); - bundle.main.read_object(ob)?.parse() - } - 1 => { - let file = bundle.shared_assets.as_mut().ok_or(anyhow!( - "shared assets referenced but not included in bundle" - ))?; - let ob = file - .objects - .iter() - .find(|o| o.path_id == self.path_id) - .ok_or(anyhow!("object with path id {} not found", self.path_id))? - .to_owned(); - file.read_object(ob)?.parse() - } - _ => unimplemented!(), + let main_file = match (self.source_file, self.file_id) { + (0, 0) => true, + (0, 1) => false, + (1, 0) => false, + _ => unreachable!(), + }; + if main_file { + let ob = bundle + .main + .objects + .iter() + .find(|o| o.path_id == self.path_id) + .ok_or(anyhow!("object with path id {} not found", self.path_id))? + .to_owned(); + bundle.main.read_object(ob)?.parse() + } else { + let file = bundle.shared_assets.as_mut().ok_or(anyhow!( + "shared assets referenced but not included in bundle" + ))?; + let ob = file + .objects + .iter() + .find(|o| o.path_id == self.path_id) + .ok_or(anyhow!("object with path id {} not found", self.path_id))? + .to_owned(); + file.read_object(ob)?.parse() } } } diff --git a/src/classes/streaminginfo.rs b/src/classes/streaminginfo.rs index e308f1c..d593a5b 100644 --- a/src/classes/streaminginfo.rs +++ b/src/classes/streaminginfo.rs @@ -28,7 +28,10 @@ impl FromValue for StreamingInfo { impl StreamingInfo { pub fn read(&self, fs: &UnityFS) -> Result> { if !self.path.starts_with("archive:") { - bail!("StreamingInfo path does not start on archive:") + bail!( + "StreamingInfo path does not start on 'archive:' ({:?})", + self.path + ) } let nodeinfo = fs .header diff --git a/src/object/helper.rs b/src/object/helper.rs index 74d18ea..4aba67d 100644 --- a/src/object/helper.rs +++ b/src/object/helper.rs @@ -104,7 +104,7 @@ impl Value { V::Array(values.into_iter().map(|e| V::Number(e.into())).collect()) } Value::Array(values) => V::Array(values.into_iter().map(Value::to_json).collect()), - Value::Object { class, fields } => V::Object( + Value::Object { class, fields, .. } => V::Object( fields .into_iter() .map(|(k, v)| (k, v.to_json())) diff --git a/src/object/mod.rs b/src/object/mod.rs index efc1544..08f76cd 100644 --- a/src/object/mod.rs +++ b/src/object/mod.rs @@ -21,6 +21,7 @@ pub enum Value { Array(Vec), Object { class: String, + file: usize, fields: BTreeMap, }, Typeless(Vec), diff --git a/src/object/parser.rs b/src/object/parser.rs index b9cc1d4..27cb975 100644 --- a/src/object/parser.rs +++ b/src/object/parser.rs @@ -11,7 +11,7 @@ impl Value { T::from_value(self) } pub fn as_class(self, name: &'static str) -> Result { - if let Value::Object { class, fields } = self { + if let Value::Object { class, fields, .. } = self { if class == name { Ok(Fields { class: name, diff --git a/src/object/read.rs b/src/object/read.rs index 641bdcc..c41163a 100644 --- a/src/object/read.rs +++ b/src/object/read.rs @@ -7,7 +7,12 @@ use std::io::Seek; use std::{collections::BTreeMap, io::Read}; impl Value { - pub fn read(ty: &TypeTreeNode, e: Endianness, data: &mut (impl Read + Seek)) -> Result { + pub fn read( + ty: &TypeTreeNode, + e: Endianness, + file: usize, + data: &mut (impl Read + Seek), + ) -> Result { let mut align = false; let pos_before = data.stream_position()?; let r = match ty.type_string.as_str() { @@ -36,7 +41,7 @@ impl Value { Ok(Value::F64(data.read_f64(e)?)) } "string" => { - let Value::Array(arr) = Value::read(&ty.children[0], e, data)? else { + let Value::Array(arr) = Value::read(&ty.children[0], e, file, data)? else { unreachable!() }; let bytes = arr @@ -51,13 +56,13 @@ impl Value { "Array" => { align |= ty.children[0].post_align(); assert_eq!(ty.byte_size, -1); - let Value::I32(size) = Value::read(&ty.children[0], e, data)? else { + let Value::I32(size) = Value::read(&ty.children[0], e, file, data)? else { unreachable!() }; trace!("array of size {size}"); let mut elems = Vec::new(); for _ in 0..size { - elems.push(Value::read(&ty.children[1], e, data)?); + elems.push(Value::read(&ty.children[1], e, file, data)?); } Ok(Value::Array(elems)) } @@ -73,10 +78,11 @@ impl Value { } let mut fields = BTreeMap::new(); for c in &ty.children { - fields.insert(c.name_string.clone(), Value::read(&c, e, data)?); + fields.insert(c.name_string.clone(), Value::read(&c, e, file, data)?); } Ok(Value::Object { fields, + file, class: ty.type_string.clone(), }) } diff --git a/src/serialized_file.rs b/src/serialized_file.rs index fa17b24..a37ff46 100644 --- a/src/serialized_file.rs +++ b/src/serialized_file.rs @@ -58,6 +58,7 @@ pub struct External { pub struct SerializedFile { pub file: T, + pub file_source_id: usize, pub header: SerializedFileHeader, pub types: Vec, pub externals: Vec, @@ -138,7 +139,7 @@ impl SerializedFileHeader { } impl SerializedFile { - pub fn read(mut file: T) -> Result> { + pub fn read(mut file: T, file_source_id: usize) -> Result> { let h = SerializedFileHeader::read(&mut file)?; let e = h.endianness; @@ -318,6 +319,7 @@ impl SerializedFile { objects, scripts, user_string, + file_source_id, }) } @@ -356,7 +358,12 @@ impl SerializedFile { .type_tree .as_ref() .ok_or(anyhow!("type tree missing"))?; - Value::read(typetree, self.endianness, &mut self.file) + Value::read( + typetree, + self.endianness, + self.file_source_id, + &mut self.file, + ) } pub fn all_objects_of_class(&self, class_name: &str) -> impl Iterator { -- cgit v1.2.3-70-g09d2