diff --git a/Cargo.lock b/Cargo.lock index ae74aea..7616a07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2341,11 +2341,9 @@ dependencies = [ [[package]] name = "strafesnet_deferred_loader" -version = "0.4.1" +version = "0.5.0" dependencies = [ "strafesnet_common", - "url", - "vbsp", ] [[package]] diff --git a/lib/deferred_loader/Cargo.toml b/lib/deferred_loader/Cargo.toml index de729c7..0ab812d 100644 --- a/lib/deferred_loader/Cargo.toml +++ b/lib/deferred_loader/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strafesnet_deferred_loader" -version = "0.4.1" +version = "0.5.0" edition = "2021" repository = "https://git.itzana.me/StrafesNET/strafe-project" license = "MIT OR Apache-2.0" @@ -9,13 +9,5 @@ authors = ["Rhys Lloyd <krakow20@gmail.com>"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[features] -default = ["legacy"] -legacy = ["dep:url","dep:vbsp"] -roblox = [] -source = ["dep:vbsp"] - [dependencies] strafesnet_common = { path = "../common", registry = "strafesnet" } -url = { version = "2.5.2", optional = true } -vbsp = { version = "0.6.0", optional = true } diff --git a/lib/deferred_loader/src/deferred_loader.rs b/lib/deferred_loader/src/deferred_loader.rs new file mode 100644 index 0000000..345e4aa --- /dev/null +++ b/lib/deferred_loader/src/deferred_loader.rs @@ -0,0 +1,109 @@ +use std::collections::HashMap; +use crate::loader::Loader; +use crate::mesh::Meshes; +use crate::texture::{RenderConfigs,Texture}; +use strafesnet_common::model::{Mesh,MeshId,RenderConfig,RenderConfigId,TextureId}; + +pub enum LoadFailureMode{ + DefaultToNone, + Fatal, +} + +pub struct RenderConfigDeferredLoader<H>{ + texture_count:u32, + render_configs:Vec<RenderConfig>, + render_config_id_from_asset_id:HashMap<Option<H>,RenderConfigId>, +} +impl<H> RenderConfigDeferredLoader<H>{ + pub fn new()->Self{ + Self{ + texture_count:0, + render_configs:Vec::new(), + render_config_id_from_asset_id:HashMap::new(), + } + } +} + +impl<H:core::hash::Hash+Eq> RenderConfigDeferredLoader<H>{ + pub fn acquire_render_config_id(&mut self,index:Option<H>)->RenderConfigId{ + let some_texture=index.is_some(); + *self.render_config_id_from_asset_id.entry(index).or_insert_with(||{ + //create the render config. + let render_config=if some_texture{ + let render_config=RenderConfig::texture(TextureId::new(self.texture_count)); + self.texture_count+=1; + render_config + }else{ + RenderConfig::default() + }; + let render_id=RenderConfigId::new(self.render_configs.len() as u32); + self.render_configs.push(render_config); + render_id + }) + } + pub fn into_render_configs<L:Loader<Index=H,Resource=Texture>>(mut self,loader:&mut L,failure_mode:LoadFailureMode)->Result<RenderConfigs,L::Error>{ + let mut sorted_textures=vec![None;self.texture_count as usize]; + for (index_option,render_config_id) in self.render_config_id_from_asset_id{ + let render_config=&mut self.render_configs[render_config_id.get() as usize]; + if let (Some(index),Some(texture_id))=(index_option,render_config.texture){ + let resource_result=loader.load(index); + let texture=match failure_mode{ + // if texture fails to load, use no texture + LoadFailureMode::DefaultToNone=>match resource_result{ + Ok(texture)=>Some(texture), + Err(e)=>{ + render_config.texture=None; + println!("Error loading texture: {e}"); + None + }, + }, + // loading failure is fatal + LoadFailureMode::Fatal=>Some(resource_result?) + }; + sorted_textures[texture_id.get() as usize]=texture; + } + } + Ok(RenderConfigs::new( + sorted_textures, + self.render_configs, + )) + } +} + +pub struct MeshDeferredLoader<H>{ + mesh_id_from_asset_id:HashMap<H,MeshId>, +} +impl<H> MeshDeferredLoader<H>{ + pub fn new()->Self{ + Self{ + mesh_id_from_asset_id:HashMap::new(), + } + } +} + +impl<H:core::hash::Hash+Eq> MeshDeferredLoader<H>{ + pub fn acquire_mesh_id(&mut self,index:H)->MeshId{ + let mesh_id=MeshId::new(self.mesh_id_from_asset_id.len() as u32); + *self.mesh_id_from_asset_id.entry(index).or_insert(mesh_id) + } + pub fn into_meshes<L:Loader<Index=H,Resource=Mesh>>(self,loader:&mut L,failure_mode:LoadFailureMode)->Result<Meshes,L::Error>{ + let mut mesh_list=vec![None;self.mesh_id_from_asset_id.len()]; + for (index,mesh_id) in self.mesh_id_from_asset_id{ + let resource_result=loader.load(index); + let mesh=match failure_mode{ + // if mesh fails to load, use no mesh + LoadFailureMode::DefaultToNone=>match resource_result{ + Ok(mesh)=>Some(mesh), + Err(e)=>{ + println!("Error loading mesh: {e}"); + None + }, + }, + // loading failure is fatal + LoadFailureMode::Fatal=>Some(resource_result?) + }; + mesh_list[mesh_id.get() as usize]=mesh; + } + Ok(Meshes::new(mesh_list)) + } +} diff --git a/lib/deferred_loader/src/lib.rs b/lib/deferred_loader/src/lib.rs index 767528a..6510201 100644 --- a/lib/deferred_loader/src/lib.rs +++ b/lib/deferred_loader/src/lib.rs @@ -1,34 +1,5 @@ -#[cfg(feature="legacy")] -mod roblox_legacy; -#[cfg(feature="legacy")] -mod source_legacy; -#[cfg(feature="roblox")] -mod roblox; -#[cfg(feature="source")] -mod source; - -#[cfg(any(feature="roblox",feature="legacy"))] -pub mod rbxassetid; +pub mod mesh; +pub mod loader; pub mod texture; -#[cfg(any(feature="source",feature="legacy"))] -pub mod valve_mesh; -#[cfg(any(feature="roblox",feature="legacy"))] -pub mod roblox_mesh; - -#[cfg(feature="legacy")] -pub fn roblox_legacy()->roblox_legacy::Loader{ - roblox_legacy::Loader::new() -} -#[cfg(feature="legacy")] -pub fn source_legacy()->source_legacy::Loader{ - source_legacy::Loader::new() -} -#[cfg(feature="roblox")] -pub fn roblox()->roblox::Loader{ - roblox::Loader::new() -} -#[cfg(feature="source")] -pub fn source()->source::Loader{ - source::Loader::new() -} +pub mod deferred_loader; diff --git a/lib/deferred_loader/src/loader.rs b/lib/deferred_loader/src/loader.rs new file mode 100644 index 0000000..adc9710 --- /dev/null +++ b/lib/deferred_loader/src/loader.rs @@ -0,0 +1,8 @@ +use std::error::Error; + +pub trait Loader{ + type Error:Error; + type Index; + type Resource; + fn load(&mut self,index:Self::Index)->Result<Self::Resource,Self::Error>; +} diff --git a/lib/deferred_loader/src/mesh.rs b/lib/deferred_loader/src/mesh.rs new file mode 100644 index 0000000..d6a0e5f --- /dev/null +++ b/lib/deferred_loader/src/mesh.rs @@ -0,0 +1,17 @@ +use strafesnet_common::model::{Mesh,MeshId}; + +pub struct Meshes{ + meshes:Vec<Option<Mesh>>, +} +impl Meshes{ + pub(crate) const fn new(meshes:Vec<Option<Mesh>>)->Self{ + Self{ + meshes, + } + } + pub fn consume(self)->impl Iterator<Item=(MeshId,Mesh)>{ + self.meshes.into_iter().enumerate().filter_map(|(mesh_id,maybe_mesh)| + maybe_mesh.map(|mesh|(MeshId::new(mesh_id as u32),mesh)) + ) + } +} diff --git a/lib/deferred_loader/src/roblox.rs b/lib/deferred_loader/src/roblox.rs deleted file mode 100644 index e69de29..0000000 diff --git a/lib/deferred_loader/src/roblox_legacy.rs b/lib/deferred_loader/src/roblox_legacy.rs deleted file mode 100644 index a6480fe..0000000 --- a/lib/deferred_loader/src/roblox_legacy.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::io::Read; -use std::collections::HashMap; -use crate::roblox_mesh; -use crate::texture::{RenderConfigs,Texture}; -use strafesnet_common::model::{MeshId,RenderConfig,RenderConfigId,TextureId}; -use crate::rbxassetid::RobloxAssetId; - -#[derive(Default)] -pub struct RenderConfigLoader{ - texture_count:u32, - render_configs:Vec<RenderConfig>, - render_config_id_from_asset_id:HashMap<Option<RobloxAssetId>,RenderConfigId>, -} - -impl RenderConfigLoader{ - pub fn acquire_render_config_id(&mut self,name:Option<&str>)->RenderConfigId{ - let render_id=RenderConfigId::new(self.render_config_id_from_asset_id.len() as u32); - let index=name.and_then(|name|{ - match name.parse::<RobloxAssetId>(){ - Ok(asset_id)=>Some(asset_id), - Err(e)=>{ - println!("Failed to parse AssetId: {e}"); - None - }, - } - }); - *self.render_config_id_from_asset_id.entry(index).or_insert_with(||{ - //create the render config. - let render_config=if name.is_some(){ - let render_config=RenderConfig::texture(TextureId::new(self.texture_count)); - self.texture_count+=1; - render_config - }else{ - RenderConfig::default() - }; - self.render_configs.push(render_config); - render_id - }) - } -} - -#[derive(Default)] -pub struct MeshLoader{ - mesh_id_from_asset_id:HashMap<Option<RobloxAssetId>,MeshId>, -} - -impl MeshLoader{ - pub fn acquire_mesh_id(&mut self,name:&str)->MeshId{ - let mesh_id=MeshId::new(self.mesh_id_from_asset_id.len() as u32); - let index=match name.parse::<RobloxAssetId>(){ - Ok(asset_id)=>Some(asset_id), - Err(e)=>{ - println!("Failed to parse AssetId: {e}"); - None - }, - }; - *self.mesh_id_from_asset_id.entry(index).or_insert(mesh_id) - } - pub fn load_meshes(&mut self)->Result<roblox_mesh::Meshes,std::io::Error>{ - let mut mesh_data=vec![None;self.mesh_id_from_asset_id.len()]; - for (asset_id_option,mesh_id) in &self.mesh_id_from_asset_id{ - if let Some(asset_id)=asset_id_option{ - if let Ok(mut file)=std::fs::File::open(format!("meshes/{}",asset_id.0)){ - //TODO: parallel - let mut data=Vec::<u8>::new(); - file.read_to_end(&mut data)?; - mesh_data[mesh_id.get() as usize]=Some(roblox_mesh::RobloxMeshData::new(data)); - }else{ - println!("[roblox_legacy] no mesh name={}",asset_id.0); - } - } - } - Ok(roblox_mesh::Meshes::new(mesh_data)) - } -} - -pub struct Loader{ - render_config_loader:RenderConfigLoader, - mesh_loader:MeshLoader, -} -impl Loader{ - pub fn new()->Self{ - Self{ - render_config_loader:RenderConfigLoader::default(), - mesh_loader:MeshLoader::default(), - } - } - pub fn get_inner_mut(&mut self)->(&mut RenderConfigLoader,&mut MeshLoader){ - (&mut self.render_config_loader,&mut self.mesh_loader) - } - pub fn into_render_configs(mut self)->Result<RenderConfigs,std::io::Error>{ - let mut sorted_textures=vec![None;self.render_config_loader.texture_count as usize]; - for (asset_id_option,render_config_id) in self.render_config_loader.render_config_id_from_asset_id{ - let render_config=self.render_config_loader.render_configs.get_mut(render_config_id.get() as usize).unwrap(); - if let (Some(asset_id),Some(texture_id))=(asset_id_option,render_config.texture){ - if let Ok(mut file)=std::fs::File::open(format!("textures/{}.dds",asset_id.0)){ - //TODO: parallel - let mut data=Vec::<u8>::new(); - file.read_to_end(&mut data)?; - sorted_textures[texture_id.get() as usize]=Some(Texture::ImageDDS(data)); - }else{ - //texture failed to load - render_config.texture=None; - } - } - } - Ok(RenderConfigs::new( - sorted_textures, - self.render_config_loader.render_configs, - )) - } -} diff --git a/lib/deferred_loader/src/roblox_mesh.rs b/lib/deferred_loader/src/roblox_mesh.rs deleted file mode 100644 index cdb545f..0000000 --- a/lib/deferred_loader/src/roblox_mesh.rs +++ /dev/null @@ -1,30 +0,0 @@ -use strafesnet_common::model::MeshId; - -#[derive(Clone)] -pub struct RobloxMeshData(Vec<u8>); -impl RobloxMeshData{ - pub(crate) fn new(data:Vec<u8>)->Self{ - Self(data) - } - pub fn get(self)->Vec<u8>{ - self.0 - } -} -pub struct Meshes{ - meshes:Vec<Option<RobloxMeshData>>, -} -impl Meshes{ - pub(crate) const fn new(meshes:Vec<Option<RobloxMeshData>>)->Self{ - Self{ - meshes, - } - } - pub fn get_texture(&self,texture_id:MeshId)->Option<&RobloxMeshData>{ - self.meshes.get(texture_id.get() as usize)?.as_ref() - } - pub fn into_iter(self)->impl Iterator<Item=(MeshId,RobloxMeshData)>{ - self.meshes.into_iter().enumerate().filter_map(|(mesh_id,maybe_mesh)| - maybe_mesh.map(|mesh|(MeshId::new(mesh_id as u32),mesh)) - ) - } -} \ No newline at end of file diff --git a/lib/deferred_loader/src/source_legacy.rs b/lib/deferred_loader/src/source_legacy.rs deleted file mode 100644 index fc1474e..0000000 --- a/lib/deferred_loader/src/source_legacy.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::io::Read; -use std::collections::HashMap; -use crate::valve_mesh; -use crate::texture::{Texture,RenderConfigs}; -use strafesnet_common::model::{MeshId,TextureId,RenderConfig,RenderConfigId}; - -pub struct RenderConfigLoader{ - texture_count:u32, - render_configs:Vec<RenderConfig>, - texture_paths:HashMap<Option<Box<str>>,RenderConfigId>, -} -impl RenderConfigLoader{ - pub fn acquire_render_config_id(&mut self,name:Option<&str>)->RenderConfigId{ - let render_id=RenderConfigId::new(self.texture_paths.len() as u32); - *self.texture_paths.entry(name.map(Into::into)).or_insert_with(||{ - //create the render config. - let render_config=if name.is_some(){ - let render_config=RenderConfig::texture(TextureId::new(self.texture_count)); - self.texture_count+=1; - render_config - }else{ - RenderConfig::default() - }; - self.render_configs.push(render_config); - render_id - }) - } -} -pub struct MeshLoader{ - mesh_paths:HashMap<Box<str>,MeshId>, -} -impl MeshLoader{ - pub fn acquire_mesh_id(&mut self,name:&str)->MeshId{ - let mesh_id=MeshId::new(self.mesh_paths.len() as u32); - *self.mesh_paths.entry(name.into()).or_insert(mesh_id) - } - //load_meshes should look like load_textures - pub fn load_meshes(&mut self,bsp:&vbsp::Bsp)->valve_mesh::Meshes{ - let mut mesh_data=vec![None;self.mesh_paths.len()]; - for (mesh_path,mesh_id) in &self.mesh_paths{ - let mesh_path_lower=mesh_path.to_lowercase(); - //.mdl, .vvd, .dx90.vtx - let path=std::path::PathBuf::from(mesh_path_lower.as_str()); - let mut vvd_path=path.clone(); - let mut vtx_path=path.clone(); - vvd_path.set_extension("vvd"); - vtx_path.set_extension("dx90.vtx"); - match (bsp.pack.get(mesh_path_lower.as_str()),bsp.pack.get(vvd_path.as_os_str().to_str().unwrap()),bsp.pack.get(vtx_path.as_os_str().to_str().unwrap())){ - (Ok(Some(mdl_file)),Ok(Some(vvd_file)),Ok(Some(vtx_file)))=>{ - mesh_data[mesh_id.get() as usize]=Some(valve_mesh::ModelData{ - mdl:valve_mesh::MdlData::new(mdl_file), - vtx:valve_mesh::VtxData::new(vtx_file), - vvd:valve_mesh::VvdData::new(vvd_file), - }); - }, - _=>println!("no model name={}",mesh_path), - } - } - valve_mesh::Meshes::new(mesh_data) - } -} - -pub struct Loader{ - render_config_loader:RenderConfigLoader, - mesh_loader:MeshLoader, -} -impl Loader{ - pub fn new()->Self{ - Self{ - render_config_loader:RenderConfigLoader{ - texture_count:0, - texture_paths:HashMap::new(), - render_configs:Vec::new(), - }, - mesh_loader:MeshLoader{mesh_paths:HashMap::new()}, - } - } - pub fn get_inner_mut(&mut self)->(&mut RenderConfigLoader,&mut MeshLoader){ - (&mut self.render_config_loader,&mut self.mesh_loader) - } - pub fn into_render_configs(mut self)->Result<RenderConfigs,std::io::Error>{ - let mut sorted_textures=vec![None;self.render_config_loader.texture_count as usize]; - for (texture_path,render_config_id) in self.render_config_loader.texture_paths{ - let render_config=self.render_config_loader.render_configs.get_mut(render_config_id.get() as usize).unwrap(); - if let (Some(texture_path),Some(texture_id))=(texture_path,render_config.texture){ - if let Ok(mut file)=std::fs::File::open(format!("textures/{}.dds",texture_path)){ - //TODO: parallel - let mut data=Vec::<u8>::new(); - file.read_to_end(&mut data)?; - sorted_textures[texture_id.get() as usize]=Some(Texture::ImageDDS(data)); - }else{ - //texture failed to load - render_config.texture=None; - } - } - } - Ok(RenderConfigs::new( - sorted_textures, - self.render_config_loader.render_configs, - )) - } -} diff --git a/lib/deferred_loader/src/valve_mesh.rs b/lib/deferred_loader/src/valve_mesh.rs deleted file mode 100644 index 15d7f40..0000000 --- a/lib/deferred_loader/src/valve_mesh.rs +++ /dev/null @@ -1,60 +0,0 @@ -use strafesnet_common::model::MeshId; - -//duplicate this code for now -#[derive(Clone)] -pub struct MdlData(Vec<u8>); -impl MdlData{ - pub const fn new(value:Vec<u8>)->Self{ - Self(value) - } - pub fn get(self)->Vec<u8>{ - self.0 - } -} -#[derive(Clone)] -pub struct VtxData(Vec<u8>); -impl VtxData{ - pub const fn new(value:Vec<u8>)->Self{ - Self(value) - } - pub fn get(self)->Vec<u8>{ - self.0 - } -} -#[derive(Clone)] -pub struct VvdData(Vec<u8>); -impl VvdData{ - pub const fn new(value:Vec<u8>)->Self{ - Self(value) - } - pub fn get(self)->Vec<u8>{ - self.0 - } -} - -#[derive(Clone)] -pub struct ModelData{ - pub mdl:MdlData, - pub vtx:VtxData, - pub vvd:VvdData, -} - -//meshes is more prone to failure -pub struct Meshes{ - meshes:Vec<Option<ModelData>>, -} -impl Meshes{ - pub(crate) const fn new(meshes:Vec<Option<ModelData>>)->Self{ - Self{ - meshes, - } - } - pub fn get_texture(&self,texture_id:MeshId)->Option<&ModelData>{ - self.meshes.get(texture_id.get() as usize)?.as_ref() - } - pub fn into_iter(self)->impl Iterator<Item=(MeshId,ModelData)>{ - self.meshes.into_iter().enumerate().filter_map(|(mesh_id,maybe_mesh)| - maybe_mesh.map(|mesh|(MeshId::new(mesh_id as u32),mesh)) - ) - } -} \ No newline at end of file diff --git a/strafe-client/Cargo.toml b/strafe-client/Cargo.toml index 64f87fe..c4663d7 100644 --- a/strafe-client/Cargo.toml +++ b/strafe-client/Cargo.toml @@ -21,7 +21,7 @@ parking_lot = "0.12.1" pollster = "0.4.0" strafesnet_bsp_loader = { path = "../lib/bsp_loader", registry = "strafesnet", optional = true } strafesnet_common = { path = "../lib/common", registry = "strafesnet" } -strafesnet_deferred_loader = { path = "../lib/deferred_loader", features = ["legacy"], registry = "strafesnet", optional = true } +strafesnet_deferred_loader = { path = "../lib/deferred_loader", registry = "strafesnet", optional = true } strafesnet_graphics = { path = "../engine/graphics", registry = "strafesnet" } strafesnet_physics = { path = "../engine/physics", registry = "strafesnet" } strafesnet_rbx_loader = { path = "../lib/rbx_loader", registry = "strafesnet", optional = true }