167 lines
5.1 KiB
Rust
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))
|
|
},
|
|
}
|
|
}
|