From a2571fe69550b00f090083b9cd39c0b36ede1140 Mon Sep 17 00:00:00 2001 From: maxcabd <84046498+maxcabd@users.noreply.github.com> Date: Sun, 28 Jul 2024 01:32:16 -0400 Subject: [PATCH] Fix issue caused by unknown chunks causing an error when reading xfbin --- src/nucc/mod.rs | 18 ++++-- src/nucc/nucc_anm.rs | 100 +++++++++++++++++------------- src/nucc/nucc_unknown.rs | 1 + src/nucc_chunk/mod.rs | 16 ++--- src/nucc_chunk/nucc_chunk_anm.rs | 103 ++++--------------------------- src/xfbin.rs | 54 ++++++---------- 6 files changed, 105 insertions(+), 187 deletions(-) diff --git a/src/nucc/mod.rs b/src/nucc/mod.rs index 2501d71..8691757 100644 --- a/src/nucc/mod.rs +++ b/src/nucc/mod.rs @@ -240,6 +240,11 @@ impl Clone for Box { let nucc_camera: &NuccCamera = self.downcast_ref().unwrap(); Box::new(nucc_camera.clone()) as Box } + + NuccChunkType::NuccChunkUnknown => { + let nucc_unknown: &NuccUnknown = self.downcast_ref().unwrap(); + Box::new(nucc_unknown.clone()) as Box + } // Add other cases for the remaining concrete types _ => panic!("Unsupported NuccStruct type for cloning"), } @@ -292,9 +297,13 @@ impl<'a> FromPyObject<'a> for Box { return Ok(Box::new(nucc_camera)); } - Err(pyo3::exceptions::PyTypeError::new_err( - "Unsupported NuccStruct type for conversion from PyAny", - )) + if let Ok(nucc_unknown) = obj.extract::() { + return Ok(Box::new(nucc_unknown)); + } + + // Add other cases for the remaining concrete types + Err(pyo3::exceptions::PyTypeError::new_err("Unsupported NuccStruct type")) + } } @@ -347,9 +356,6 @@ impl From for Box { NuccChunkType::NuccChunkAmbient => { Box::::from(converter) as Box } NuccChunkType::NuccChunkMorphModel => { Box::::from(converter) as Box } NuccChunkType::NuccChunkUnknown => { Box::::from(converter) as Box } - - - any => panic!("Unexpected NuccChunkType: {any}"), } } diff --git a/src/nucc/nucc_anm.rs b/src/nucc/nucc_anm.rs index 5fb3fee..a5634e6 100644 --- a/src/nucc/nucc_anm.rs +++ b/src/nucc/nucc_anm.rs @@ -23,7 +23,7 @@ pub struct NuccAnm { pub is_looped: bool, #[pyo3(get, set)] - pub other_entries_indices: Vec, + pub other_entries_indices: Py, #[pyo3(get, set)] pub unk_entry_indices: Vec, @@ -38,6 +38,48 @@ pub struct NuccAnm { pub entries: Py, } +#[pymethods] +impl NuccAnm { + #[new] + #[pyo3(signature = (struct_info = None, version = 121, frame_count = 0, is_looped = false, other_entries_indices = None, unk_entry_indices = None, clumps = None, coord_parents = None, entries = None))] + pub fn __new__( + py: Python, + struct_info: Option, + version: u16, + frame_count: u32, + is_looped: bool, + other_entries_indices: Option>, + unk_entry_indices: Option>, + clumps: Option>, + coord_parents: Option>, + entries: Option>, + ) -> Self { + Self { + struct_info: struct_info.unwrap_or_default(), + version, + frame_count, + is_looped, + other_entries_indices: other_entries_indices.unwrap_or(PyList::empty_bound(py).into()), + unk_entry_indices: unk_entry_indices.unwrap_or_default(), + clumps: clumps.unwrap_or(PyList::empty_bound(py).into()), + coord_parents: coord_parents.unwrap_or(PyList::empty_bound(py).into()), + entries: entries.unwrap_or(PyList::empty_bound(py).into()), + } + } + + fn __repr__(&self) -> PyResult { + Ok(format!( + "NuccAnm(struct_info={:?}, version={}, frame_count={}, is_looped={}, other_entries_indices={:?}, unk_entry_indices={:?} clumps={:?}, coord_parents={:?}, entries={:?})", + self.struct_info, self.version, self.frame_count, self.is_looped, self.other_entries_indices, self.unk_entry_indices, self.clumps, self.coord_parents, self.entries + )) + } + + fn __str__(&self) -> PyResult { + self.__repr__() + } + +} + #[derive(Debug, Clone)] #[pyclass(name = "AnmEntry")] pub struct Entry { @@ -129,47 +171,7 @@ impl Track { } -#[pymethods] -impl NuccAnm { - #[new] - #[pyo3(signature = (struct_info = None, version = 121, frame_count = 0, is_looped = false, other_entries_indices = None, unk_entry_indices = None, clumps = None, coord_parents = None, entries = None))] - pub fn __new__( - py: Python, - struct_info: Option, - version: u16, - frame_count: u32, - is_looped: bool, - other_entries_indices: Option>, - unk_entry_indices: Option>, - clumps: Option>, - coord_parents: Option>, - entries: Option>, - ) -> Self { - Self { - struct_info: struct_info.unwrap_or_default(), - version, - frame_count, - is_looped, - other_entries_indices: other_entries_indices.unwrap_or_default(), - unk_entry_indices: unk_entry_indices.unwrap_or_default(), - clumps: clumps.unwrap_or(PyList::empty_bound(py).into()), - coord_parents: coord_parents.unwrap_or(PyList::empty_bound(py).into()), - entries: entries.unwrap_or(PyList::empty_bound(py).into()), - } - } - - fn __repr__(&self) -> PyResult { - Ok(format!( - "NuccAnm(struct_info={:?}, version={}, frame_count={}, is_looped={}, other_entries_indices={:?}, unk_entry_indices={:?} clumps={:?}, coord_parents={:?}, entries={:?})", - self.struct_info, self.version, self.frame_count, self.is_looped, self.other_entries_indices, self.unk_entry_indices, self.clumps, self.coord_parents, self.entries - )) - } - fn __str__(&self) -> PyResult { - self.__repr__() - } - -} impl_nucc_info!(NuccAnm, struct_info); @@ -186,6 +188,14 @@ impl From for NuccAnm { .map(|c| *c) .ok() .unwrap(); + + let other_entries_indices: Py = Python::with_gil(|py| { + let other_entries_indices: Vec = chunk.other_entries_indices.iter().map(|&value| { + value.into_py(py) + }).collect(); + + PyList::new_bound(py, other_entries_indices).into() + }); let clumps: Py = Python::with_gil(|py| { @@ -261,7 +271,7 @@ impl From for NuccAnm { frame_count: chunk.frame_count, is_looped: chunk.is_looped == 1, clumps, - other_entries_indices: chunk.other_entries_indices, + other_entries_indices, unk_entry_indices: chunk.unk_entry_indices, coord_parents, entries, @@ -279,6 +289,10 @@ impl From for Box { let anm = nucc_struct.downcast::().map(|s| *s).ok().unwrap(); + let other_entries_indices: Vec = Python::with_gil(|py| { + anm.other_entries_indices.extract(py).unwrap() + }); + let clumps: Vec = Python::with_gil(|py| { anm.clumps.extract(py).unwrap() }); @@ -320,7 +334,7 @@ impl From for Box { chunk.frame_count = anm.frame_count; chunk.is_looped = if anm.is_looped { 1 } else { 0 }; chunk.clumps = clumps; - chunk.other_entries_indices = anm.other_entries_indices; + chunk.other_entries_indices = other_entries_indices; chunk.unk_entry_indices = anm.unk_entry_indices; chunk.coord_parents = coord_parents; chunk.entries = anm_entries; diff --git a/src/nucc/nucc_unknown.rs b/src/nucc/nucc_unknown.rs index 5994a9a..dbec1e6 100644 --- a/src/nucc/nucc_unknown.rs +++ b/src/nucc/nucc_unknown.rs @@ -3,6 +3,7 @@ use super::*; use pyo3::prelude::*; #[pyclass] +#[derive(Debug, Clone)] pub struct NuccUnknown { pub struct_info: NuccStructInfo, pub version: u16, diff --git a/src/nucc_chunk/mod.rs b/src/nucc_chunk/mod.rs index 9b29f75..f1bc607 100644 --- a/src/nucc_chunk/mod.rs +++ b/src/nucc_chunk/mod.rs @@ -54,8 +54,7 @@ pub trait NuccChunk: Downcast + fmt::Debug { // set the version of the chunk Ok((input.into(), Box::new(result) as Box)) - - + } fn write_boxed( @@ -94,9 +93,6 @@ pub enum NuccChunkType { NuccChunkAmbient, NuccChunkMorphModel, NuccChunkUnknown, - - - } impl Default for NuccChunkType { @@ -116,7 +112,6 @@ impl NuccChunkType { NuccChunkType::NuccChunkPage => NuccChunkPage::read_boxed(&data, version), NuccChunkType::NuccChunkIndex => Ok((data, Box::new(NuccChunkIndex))), NuccChunkType::NuccChunkBinary => NuccChunkBinary::read_boxed(&data, version), - NuccChunkType::NuccChunkAnm => NuccChunkAnm::read_boxed(&data, version), // Fix: Change `u16` to `()` NuccChunkType::NuccChunkAnmStrm => NuccChunkAnmStrm::read_boxed(&data, version), NuccChunkType::NuccChunkAnmStrmFrame => { NuccChunkAnmStrmFrame::read_boxed(&data, version)} @@ -126,9 +121,8 @@ impl NuccChunkType { NuccChunkType::NuccChunkLayerSet => NuccChunkLayerSet::read_boxed(&data, version), NuccChunkType::NuccChunkAmbient => NuccChunkAmbient::read_boxed(&data, version), NuccChunkType::NuccChunkMorphModel => NuccChunkMorphModel::read_boxed(&data, version), - - - NuccChunkType::NuccChunkUnknown => Ok(( + // If the chunk type is unknown, return the data as an unknown chunk + _ => Ok(( data.clone(), Box::new(NuccChunkUnknown { version, @@ -157,8 +151,8 @@ impl NuccChunkType { NuccChunkType::NuccChunkLayerSet => { NuccChunkLayerSet::write_boxed(boxed, &mut output, version)?; } NuccChunkType::NuccChunkAmbient => { NuccChunkAmbient::write_boxed(boxed, &mut output, version)?; } NuccChunkType::NuccChunkMorphModel => { NuccChunkMorphModel::write_boxed(boxed, &mut output, version)?; } - - NuccChunkType::NuccChunkUnknown => { + // If the chunk type is unknown, return the data as an unknown chunk + _ => { let unknown = boxed .downcast::() .map(|x| x.data) diff --git a/src/nucc_chunk/nucc_chunk_anm.rs b/src/nucc_chunk/nucc_chunk_anm.rs index 2ca98e2..c9188ec 100644 --- a/src/nucc_chunk/nucc_chunk_anm.rs +++ b/src/nucc_chunk/nucc_chunk_anm.rs @@ -425,20 +425,22 @@ fn read_track_data( keyframes.push(NuccAnmKey::Vec4Linear { frame, values: (x, y, z, w) }); } - - NuccAnmKeyFormat::FloatFixed => { let x = reader.read_be::()?; keyframes.push(NuccAnmKey::Float { values: x }); } + NuccAnmKeyFormat::FloatTable => { + let x = reader.read_be::()?; + keyframes.push(NuccAnmKey::Float { values: x }); + } + NuccAnmKeyFormat::FloatLinear => { let frame = reader.read_be::()?; let x = reader.read_be::()?; keyframes.push(NuccAnmKey::FloatLinear { frame, values: x }); } - NuccAnmKeyFormat::OpacityShortTable => { let x = reader.read_be::()?; keyframes.push(NuccAnmKey::I16Vec { values: x }); @@ -457,101 +459,20 @@ fn read_track_data( let b = reader.read_be::()?; keyframes.push(NuccAnmKey::Color { values: (r, g, b) }); } - - - _ => todo!(), + // Return an error saying that the key format is not supported and the key format itself + _ => { + dbg!(format!("Key format {:?} is not supported", header.key_format)); + } } - - - - - + } Ok(keyframes) } -fn write_fcurve_data( - anm_key: NuccAnmKeyFormat, - values: NuccAnmKey, - writer: &mut R, - wo: &WriteOptions, - - _: () -) -> BinResult<()> { - - match (anm_key, values) { - (NuccAnmKeyFormat::Vector3Fixed, NuccAnmKey::Vec3 { values }) | - (NuccAnmKeyFormat::EulerXYZFixed, NuccAnmKey::Vec3 { values }) | - (NuccAnmKeyFormat::Vector3Table, NuccAnmKey::Vec3 { values }) => { - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::Vector3Linear, NuccAnmKey::Vec3Linear { frame, values }) => { - frame.write_options(writer, wo, ())?; - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::QuaternionLinear, NuccAnmKey::Vec4Linear { frame, values }) => { - frame.write_options(writer, wo, ())?; - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - values.3.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::FloatFixed, NuccAnmKey::Float { values }) | - (NuccAnmKeyFormat::FloatTable, NuccAnmKey::Float { values}) | - (NuccAnmKeyFormat::FloatTableNoInterp, NuccAnmKey::Float { values}) => { - values.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::FloatLinear, NuccAnmKey::FloatLinear { frame, values }) => { - frame.write_options(writer, wo, ())?; - values.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::OpacityShortTable, NuccAnmKey::I16Vec { values }) | - (NuccAnmKeyFormat::OpacityShortTableNoInterp, NuccAnmKey::I16Vec { values }) => { - values.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::ScaleShortTable, NuccAnmKey::I16Vec3 { values }) => { - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::QuaternionShortTable, NuccAnmKey::ShortVec4 { values }) | - (NuccAnmKeyFormat::QuaternionShortTableNoInterp, NuccAnmKey::ShortVec4 { values }) => { - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - values.3.write_options(writer, wo, ())?; - } - - (NuccAnmKeyFormat::ColorRGBTable, NuccAnmKey::Color { values }) => { - values.0.write_options(writer, wo, ())?; - values.1.write_options(writer, wo, ())?; - values.2.write_options(writer, wo, ())?; - } - // Handle other NuccAnmKeyFormat cases and Keyframe variants... - _ => todo!(), - } - - Ok(()) -} - - - - impl NuccChunk for NuccChunkAnm { fn chunk_type(&self) -> NuccChunkType { NuccChunkType::NuccChunkAnm @@ -560,6 +481,4 @@ impl NuccChunk for NuccChunkAnm { fn version(&self) -> u16 { self.version } - - -} +} \ No newline at end of file diff --git a/src/xfbin.rs b/src/xfbin.rs index e2d1a95..6de3ecb 100644 --- a/src/xfbin.rs +++ b/src/xfbin.rs @@ -126,11 +126,9 @@ impl XfbinPage { self.structs.extract(py).unwrap() }); - let mut struct_infos = IndexMap::::new(); let mut struct_references = IndexMap::::new(); - let struct_infos_vec: Vec = Python::with_gil(|py| { self.struct_infos.extract(py).unwrap() }); @@ -144,7 +142,6 @@ impl XfbinPage { struct_references.extend(struct_references_vec.iter().enumerate().map(|(i, s)| ((*s).clone(), i as u32))); } - (structs, struct_infos, struct_references) } @@ -155,14 +152,11 @@ impl From for Xfbin { fn from(xfbin: XfbinFile) -> Self { let mut pages = Vec::new(); - - // Create a new XfbinPage PyObj let mut page = Python::with_gil( |py| XfbinPage::__new__(py, None, None, None) ); - let chunk_names = xfbin .index .chunk_names @@ -295,11 +289,6 @@ impl From for Xfbin { } - - - - - let pages = Python::with_gil(|py| { PyList::new_bound(py, pages.iter().map(|page| { Py::new(py, page.clone()).unwrap() @@ -370,7 +359,7 @@ impl From for XfbinFile { &mut page_struct_infos, ); - //chunks.push(null_chunk); + chunks.push(null_chunk); for nucc_struct in page_structs { let struct_info = nucc_struct.struct_info().clone(); @@ -387,7 +376,7 @@ impl From for XfbinFile { // Add nuccChunkPage map repack_struct( Box::new(NuccChunkPage::default()), - NuccChunkIndex::default_chunk_info(), + NuccChunkPage::default_chunk_info(), &mut page_struct_infos, ); @@ -398,21 +387,14 @@ impl From for XfbinFile { &mut page_struct_infos, ); - let mut map_index_count = page_struct_infos.len() as u32; - - if map_index_count < 4 { - map_index_count = (map_index_count + 3) & !3; - } - - else { - map_index_count += 1; - } + + // Create final nuccChunkPage let page_chunk = repack_struct( Box::new(NuccChunkPage { version: xfbin.version, - map_index_count, + map_index_count: page_struct_infos.len() as u32, reference_count: page_struct_references.len() as u32, }), NuccChunkPage::default_chunk_info(), @@ -421,19 +403,21 @@ impl From for XfbinFile { chunks.push(page_chunk); + for struct_info in page_struct_infos - .clone() - .into_iter() - .sorted_by_key(|(_, v)| *v) - .map(|(k, _)| k) - { - let struct_info_index = struct_infos_map.len() as u32; - chunk_map_indices.push( - *struct_infos_map - .entry(struct_info) - .or_insert(struct_info_index), - ); - } + .clone() + .into_iter() + .sorted_by_key(|(_, v)| *v) + .map(|(k, _)| k) + { + let struct_info_index = struct_infos_map.len() as u32; + chunk_map_indices.push( + *struct_infos_map + .entry(struct_info) + .or_insert(struct_info_index), + ); + + } struct_references_vec.extend( page_struct_references