diff --git a/lib/rbx_loader/src/loader.rs b/lib/rbx_loader/src/loader.rs index eb804ce..11a0448 100644 --- a/lib/rbx_loader/src/loader.rs +++ b/lib/rbx_loader/src/loader.rs @@ -60,7 +60,9 @@ pub enum MeshError{ RobloxAssetIdParse(RobloxAssetIdParseErr), Mesh(crate::mesh::Error), Union(crate::union::Error), - + DecodeBinary(rbx_binary::DecodeError), + OneChildPolicy, + MissingInstance, } impl std::fmt::Display for MeshError{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ @@ -88,6 +90,11 @@ impl From<crate::union::Error> for MeshError{ Self::Union(value) } } +impl From<rbx_binary::DecodeError> for MeshError{ + fn from(value:rbx_binary::DecodeError)->Self{ + Self::DecodeBinary(value) + } +} #[derive(Hash,Eq,PartialEq)] pub enum MeshType<'a>{ @@ -132,14 +139,41 @@ impl<'a> Loader for MeshLoader<'a>{ type Index=MeshIndex<'a>; type Resource=Mesh; fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>{ - let RobloxAssetId(asset_id)=index.content.parse()?; - let file_name=format!("meshes/{}",asset_id); - // reading the entire file is way faster than - // round tripping to disk every read from the parser - let data=read_entire_file(file_name)?; let mesh=match index.mesh_type{ - MeshType::FileMesh=>crate::mesh::convert(RobloxMeshBytes::new(data))?, - MeshType::Union{physics_data,mesh_data}=>crate::union::convert(physics_data,mesh_data)?, + MeshType::FileMesh=>{ + let RobloxAssetId(asset_id)=index.content.parse()?; + let file_name=format!("meshes/{}",asset_id); + let data=read_entire_file(file_name)?; + crate::mesh::convert(RobloxMeshBytes::new(data))? + }, + MeshType::Union{mut physics_data,mut mesh_data}=>{ + // decode asset + if !index.content.is_empty()&&(physics_data.is_empty()||mesh_data.is_empty()){ + let RobloxAssetId(asset_id)=index.content.parse()?; + let file_name=format!("unions/{}",asset_id); + let data=read_entire_file(file_name)?; + let dom=rbx_binary::from_reader(std::io::Cursor::new(data))?; + let &[referent]=dom.root().children()else{ + return Err(MeshError::OneChildPolicy); + }; + let Some(instance)=dom.get_by_ref(referent)else{ + return Err(MeshError::MissingInstance); + }; + if physics_data.is_empty(){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get("PhysicsData"){ + physics_data=data.as_ref(); + } + } + if mesh_data.is_empty(){ + if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=instance.properties.get("MeshData"){ + mesh_data=data.as_ref(); + } + } + crate::union::convert(physics_data,mesh_data)? + }else{ + crate::union::convert(physics_data,mesh_data)? + } + }, }; Ok(mesh) }