diff --git a/Cargo.lock b/Cargo.lock index b2761b0..48a1c02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2389,8 +2389,10 @@ dependencies = [ "rbx_mesh", "rbx_reflection_database", "rbx_xml", + "rbxassetid", "roblox_emulator", "strafesnet_common", + "strafesnet_deferred_loader", ] [[package]] diff --git a/lib/rbx_loader/Cargo.toml b/lib/rbx_loader/Cargo.toml index 072cabd..9ba6f7b 100644 --- a/lib/rbx_loader/Cargo.toml +++ b/lib/rbx_loader/Cargo.toml @@ -18,5 +18,7 @@ rbx_dom_weak = { version = "2.7.0", registry = "strafesnet" } rbx_mesh = "0.1.2" rbx_reflection_database = { version = "0.2.10", registry = "strafesnet" } rbx_xml = { version = "0.13.3", registry = "strafesnet" } +rbxassetid = { version = "0.1.0", path = "../rbxassetid" } roblox_emulator = { path = "../roblox_emulator", registry = "strafesnet" } strafesnet_common = { path = "../common", registry = "strafesnet" } +strafesnet_deferred_loader = { version = "0.5.0", path = "../deferred_loader" } diff --git a/lib/rbx_loader/src/lib.rs b/lib/rbx_loader/src/lib.rs index bb73961..98a22c6 100644 --- a/lib/rbx_loader/src/lib.rs +++ b/lib/rbx_loader/src/lib.rs @@ -3,6 +3,7 @@ use rbx_dom_weak::WeakDom; mod rbx; mod mesh; +pub mod loader; mod primitives; pub mod data{ @@ -94,14 +95,4 @@ pub fn read<R:Read>(input:R)->Result<Model,ReadError>{ //ConvertError -pub fn convert<AcquireRenderConfigId,AcquireMeshId>( - dom:impl AsRef<WeakDom>, - acquire_render_config_id:AcquireRenderConfigId, - acquire_mesh_id:AcquireMeshId -)->rbx::PartialMap1 -where - AcquireRenderConfigId:FnMut(Option<&str>)->strafesnet_common::model::RenderConfigId, - AcquireMeshId:FnMut(&str)->strafesnet_common::model::MeshId, -{ - rbx::convert(&dom.as_ref(),acquire_render_config_id,acquire_mesh_id) -} +pub use rbx::convert; diff --git a/lib/rbx_loader/src/loader.rs b/lib/rbx_loader/src/loader.rs new file mode 100644 index 0000000..099a080 --- /dev/null +++ b/lib/rbx_loader/src/loader.rs @@ -0,0 +1,102 @@ +use std::io::Read; +use rbxassetid::{RobloxAssetId,RobloxAssetIdParseErr}; +use strafesnet_common::model::Mesh; +use strafesnet_deferred_loader::{loader::Loader,texture::Texture}; + +use crate::data::RobloxMeshBytes; + +#[allow(dead_code)] +#[derive(Debug)] +pub enum TextureError{ + Io(std::io::Error), + RobloxAssetIdParse(RobloxAssetIdParseErr), +} +impl std::fmt::Display for TextureError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for TextureError{} +impl From<std::io::Error> for TextureError{ + fn from(value:std::io::Error)->Self{ + Self::Io(value) + } +} +impl From<RobloxAssetIdParseErr> for TextureError{ + fn from(value:RobloxAssetIdParseErr)->Self{ + Self::RobloxAssetIdParse(value) + } +} + +pub struct TextureLoader<'a>(std::marker::PhantomData<&'a ()>); +impl TextureLoader<'_>{ + pub fn new()->Self{ + Self(std::marker::PhantomData) + } +} +impl<'a> Loader for TextureLoader<'a>{ + type Error=TextureError; + type Index=&'a str; + type Resource=Texture; + fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>{ + let RobloxAssetId(asset_id)=index.parse()?; + let file_name=format!("textures/{}.dds",asset_id); + let mut file=std::fs::File::open(file_name)?; + let mut data=Vec::new(); + file.read_to_end(&mut data)?; + Ok(Texture::ImageDDS(data)) + } +} + +#[allow(dead_code)] +#[derive(Debug)] +pub enum MeshError{ + Io(std::io::Error), + RobloxAssetIdParse(RobloxAssetIdParseErr), + Mesh(crate::mesh::Error) + +} +impl std::fmt::Display for MeshError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for MeshError{} +impl From<std::io::Error> for MeshError{ + fn from(value:std::io::Error)->Self{ + Self::Io(value) + } +} +impl From<RobloxAssetIdParseErr> for MeshError{ + fn from(value:RobloxAssetIdParseErr)->Self{ + Self::RobloxAssetIdParse(value) + } +} +impl From<crate::mesh::Error> for MeshError{ + fn from(value:crate::mesh::Error)->Self{ + Self::Mesh(value) + } +} + +pub struct MeshLoader<'a>(std::marker::PhantomData<&'a ()>); +impl MeshLoader<'_>{ + pub fn new()->Self{ + Self(std::marker::PhantomData) + } +} +impl<'a> Loader for MeshLoader<'a>{ + type Error=MeshError; + type Index=&'a str; + type Resource=Mesh; + fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>{ + let RobloxAssetId(asset_id)=index.parse()?; + let file_name=format!("meshes/{}",asset_id); + let mut file=std::fs::File::open(file_name)?; + // reading the entire file is way faster than + // round tripping to disk every read from the parser + let mut data=Vec::new(); + file.read_to_end(&mut data)?; + let mesh=crate::mesh::convert(RobloxMeshBytes::new(data))?; + Ok(mesh) + } +} diff --git a/lib/rbx_loader/src/rbx.rs b/lib/rbx_loader/src/rbx.rs index 643cf3d..bd5ff9a 100644 --- a/lib/rbx_loader/src/rbx.rs +++ b/lib/rbx_loader/src/rbx.rs @@ -8,6 +8,9 @@ use strafesnet_common::gameplay_attributes as attr; use strafesnet_common::integer::{self,vec3,Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3}; use strafesnet_common::model::RenderConfigId; use strafesnet_common::updatable::Updatable; +use strafesnet_deferred_loader::deferred_loader::{RenderConfigDeferredLoader,MeshDeferredLoader}; +use strafesnet_deferred_loader::mesh::Meshes; +use strafesnet_deferred_loader::texture::{RenderConfigs,Texture}; fn class_is_a(class: &str, superclass: &str) -> bool { if class==superclass { @@ -432,23 +435,18 @@ struct GetAttributesArgs{ can_collide:bool, velocity:Planar64Vec3, } -pub fn convert<AcquireRenderConfigId,AcquireMeshId>( - dom:&rbx_dom_weak::WeakDom, - mut acquire_render_config_id:AcquireRenderConfigId, - mut acquire_mesh_id:AcquireMeshId, -)->PartialMap1 -where - AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId, - AcquireMeshId:FnMut(&str)->model::MeshId, -{ - +pub fn convert<'a>( + dom:&'a rbx_dom_weak::WeakDom, + render_config_deferred_loader:&mut RenderConfigDeferredLoader<&'a str>, + mesh_deferred_loader:&mut MeshDeferredLoader<&'a str>, +)->PartialMap1{ let mut deferred_models_deferred_attributes=Vec::new(); let mut primitive_models_deferred_attributes=Vec::new(); let mut primitive_meshes=Vec::new(); let mut mesh_id_from_description=HashMap::new(); //just going to leave it like this for now instead of reworking the data structures for this whole thing - let textureless_render_group=acquire_render_config_id(None); + let textureless_render_group=render_config_deferred_loader.acquire_render_config_id(None); let mut object_refs=Vec::new(); let mut temp_objects=Vec::new(); @@ -529,7 +527,7 @@ where decal.properties.get("Color3"), decal.properties.get("Transparency"), ) { - let render_id=acquire_render_config_id(Some(content.as_ref())); + let render_id=render_config_deferred_loader.acquire_render_config_id(Some(content.as_ref())); let normal_id=normalid.to_u32(); if normal_id<6{ let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{ @@ -691,8 +689,8 @@ where object.properties.get("TextureID"), ){ ( - MeshAvailability::Deferred(acquire_render_config_id(Some(texture_asset_id.as_ref()))), - acquire_mesh_id(mesh_asset_id.as_ref()), + MeshAvailability::Deferred(render_config_deferred_loader.acquire_render_config_id(Some(texture_asset_id.as_ref()))), + mesh_deferred_loader.acquire_mesh_id(mesh_asset_id.as_ref()), ) }else{ panic!("Mesh has no Mesh or Texture"); @@ -736,7 +734,7 @@ pub struct PartialMap1{ impl PartialMap1{ pub fn add_meshpart_meshes_and_calculate_attributes( mut self, - meshpart_meshes:impl IntoIterator<Item=(model::MeshId,crate::data::RobloxMeshBytes)>, + meshpart_meshes:Meshes, )->PartialMap2{ //calculate attributes let mut modes_builder=ModesBuilder::default(); @@ -749,24 +747,16 @@ impl PartialMap1{ //decode roblox meshes //generate mesh_id_map based on meshes that failed to load let loaded_meshes:HashMap<model::MeshId,MeshWithAabb>= - meshpart_meshes.into_iter().flat_map(|(old_mesh_id,roblox_mesh_bytes)| - match crate::mesh::convert(roblox_mesh_bytes){ - Ok(mesh)=>{ - let mut aabb=strafesnet_common::aabb::Aabb::default(); - for &pos in &mesh.unique_pos{ - aabb.grow(pos); - } - Some((old_mesh_id,MeshWithAabb{ - mesh, - aabb, - })) - }, - Err(e)=>{ - println!("Error converting mesh: {e:?}"); - None - }, + meshpart_meshes.consume().map(|(old_mesh_id,mesh)|{ + let mut aabb=strafesnet_common::aabb::Aabb::default(); + for &pos in &mesh.unique_pos{ + aabb.grow(pos); } - ).collect(); + (old_mesh_id,MeshWithAabb{ + mesh, + aabb, + }) + }).collect(); let mut mesh_id_from_render_config_id=HashMap::new(); //ignore meshes that fail to load completely for now @@ -879,11 +869,11 @@ pub struct PartialMap2{ impl PartialMap2{ pub fn add_render_configs_and_textures( self, - render_configs:impl IntoIterator<Item=(model::RenderConfigId,model::RenderConfig)>, - textures:impl IntoIterator<Item=(model::TextureId,Vec<u8>)>, + render_configs:RenderConfigs, )->map::CompleteMap{ + let (textures,render_configs)=render_configs.consume(); let (textures,texture_id_map):(Vec<Vec<u8>>,HashMap<model::TextureId,model::TextureId>) - =textures.into_iter().enumerate().map(|(new_texture_id,(old_texture_id,texture))|{ + =textures.into_iter().enumerate().map(|(new_texture_id,(old_texture_id,Texture::ImageDDS(texture)))|{ (texture,(old_texture_id,model::TextureId::new(new_texture_id as u32))) }).unzip(); let render_configs=render_configs.into_iter().map(|(_render_config_id,mut render_config)|{