2025-01-20 09:14:01 -08:00

167 lines
5.1 KiB
Rust

use std::io::Read;
#[derive(Debug)]
pub enum ReadError{
#[cfg(feature="roblox")]
Roblox(strafesnet_rbx_loader::ReadError),
#[cfg(feature="source")]
Source(strafesnet_bsp_loader::ReadError),
#[cfg(feature="snf")]
StrafesNET(strafesnet_snf::Error),
#[cfg(feature="snf")]
StrafesNETMap(strafesnet_snf::map::Error),
#[cfg(feature="snf")]
StrafesNETBot(strafesnet_snf::bot::Error),
Io(std::io::Error),
UnknownFileFormat,
}
impl std::fmt::Display for ReadError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for ReadError{}
pub enum ReadFormat{
#[cfg(feature="roblox")]
Roblox(strafesnet_rbx_loader::Model),
#[cfg(feature="source")]
Source(strafesnet_bsp_loader::Bsp),
#[cfg(feature="snf")]
SNFM(strafesnet_common::map::CompleteMap),
#[cfg(feature="snf")]
SNFB(strafesnet_snf::bot::Segment),
}
pub fn read<R:Read+std::io::Seek>(input:R)->Result<ReadFormat,ReadError>{
let mut buf=std::io::BufReader::new(input);
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadError::Io)?[0..4].to_owned();
// reading the entire file is way faster than round tripping the disk constantly
let mut entire_file=Vec::new();
buf.read_to_end(&mut entire_file).map_err(ReadError::Io)?;
let cursor=std::io::Cursor::new(entire_file);
match peek.as_slice(){
#[cfg(feature="roblox")]
b"<rob"=>Ok(ReadFormat::Roblox(strafesnet_rbx_loader::read(cursor).map_err(ReadError::Roblox)?)),
#[cfg(feature="source")]
b"VBSP"=>Ok(ReadFormat::Source(strafesnet_bsp_loader::read(cursor).map_err(ReadError::Source)?)),
#[cfg(feature="snf")]
b"SNFM"=>Ok(ReadFormat::SNFM(
strafesnet_snf::read_map(cursor).map_err(ReadError::StrafesNET)?
.into_complete_map().map_err(ReadError::StrafesNETMap)?
)),
#[cfg(feature="snf")]
b"SNFB"=>Ok(ReadFormat::SNFB(
strafesnet_snf::read_bot(cursor).map_err(ReadError::StrafesNET)?
.read_all().map_err(ReadError::StrafesNETBot)?
)),
_=>Err(ReadError::UnknownFileFormat),
}
}
#[derive(Debug)]
pub enum LoadError{
ReadError(ReadError),
File(std::io::Error),
Io(std::io::Error),
}
impl std::fmt::Display for LoadError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for LoadError{}
pub enum LoadFormat{
#[cfg(feature="snf")]
Map(strafesnet_common::map::CompleteMap),
#[cfg(feature="snf")]
Bot(strafesnet_snf::bot::Segment),
}
pub fn load<P:AsRef<std::path::Path>>(path:P)->Result<LoadFormat,LoadError>{
//blocking because it's simpler...
let file=std::fs::File::open(path).map_err(LoadError::File)?;
match read(file).map_err(LoadError::ReadError)?{
#[cfg(feature="snf")]
ReadFormat::SNFB(bot)=>Ok(LoadFormat::Bot(bot)),
#[cfg(feature="snf")]
ReadFormat::SNFM(map)=>Ok(LoadFormat::Map(map)),
#[cfg(feature="roblox")]
ReadFormat::Roblox(model)=>{
let mut place=model.into_place();
place.run_scripts();
let mut loader=strafesnet_deferred_loader::roblox_legacy();
let (texture_loader,mesh_loader)=loader.get_inner_mut();
let map_step1=strafesnet_rbx_loader::convert(
&place,
|name|texture_loader.acquire_render_config_id(name),
|name|mesh_loader.acquire_mesh_id(name),
);
let meshpart_meshes=mesh_loader.load_meshes().map_err(LoadError::Io)?;
let map_step2=map_step1.add_meshpart_meshes_and_calculate_attributes(
meshpart_meshes.into_iter().map(|(mesh_id,loader_model)|
(mesh_id,strafesnet_rbx_loader::data::RobloxMeshBytes::new(loader_model.get()))
)
);
let (textures,render_configs)=loader.into_render_configs().map_err(LoadError::Io)?.consume();
let map=map_step2.add_render_configs_and_textures(
render_configs.into_iter(),
textures.into_iter().map(|(texture_id,texture)|
(texture_id,match texture{
strafesnet_deferred_loader::texture::Texture::ImageDDS(data)=>data,
})
)
);
Ok(LoadFormat::Map(map))
},
#[cfg(feature="source")]
ReadFormat::Source(bsp)=>{
let mut loader=strafesnet_deferred_loader::source_legacy();
let (texture_loader,mesh_loader)=loader.get_inner_mut();
let map_step1=strafesnet_bsp_loader::convert(
&bsp,
|name|texture_loader.acquire_render_config_id(name),
|name|mesh_loader.acquire_mesh_id(name),
);
let prop_meshes=mesh_loader.load_meshes(bsp.as_ref());
let map_step2=map_step1.add_prop_meshes(
//the type conflagulator 9000
prop_meshes.into_iter().map(|(mesh_id,loader_model)|
(mesh_id,strafesnet_bsp_loader::data::ModelData{
mdl:strafesnet_bsp_loader::data::MdlData::new(loader_model.mdl.get()),
vtx:strafesnet_bsp_loader::data::VtxData::new(loader_model.vtx.get()),
vvd:strafesnet_bsp_loader::data::VvdData::new(loader_model.vvd.get()),
})
),
|name|texture_loader.acquire_render_config_id(name),
);
let (textures,render_configs)=loader.into_render_configs().map_err(LoadError::Io)?.consume();
let map=map_step2.add_render_configs_and_textures(
render_configs.into_iter(),
textures.into_iter().map(|(texture_id,texture)|
(texture_id,match texture{
strafesnet_deferred_loader::texture::Texture::ImageDDS(data)=>data,
})
),
);
Ok(LoadFormat::Map(map))
},
}
}