bsp_loader: case folding

This commit is contained in:
Quaternions 2025-02-04 12:57:28 -08:00
parent a2a69c48d6
commit 8e91fbb08e
3 changed files with 48 additions and 19 deletions
lib/bsp_loader/src
map-tool/src

@ -45,6 +45,7 @@ impl From<loader::MeshError> for LoadError{
} }
pub struct Bsp{ pub struct Bsp{
bsp:vbsp::Bsp, bsp:vbsp::Bsp,
case_folded_file_names:std::collections::HashMap<String,String>,
} }
impl AsRef<vbsp::Bsp> for Bsp{ impl AsRef<vbsp::Bsp> for Bsp{
fn as_ref(&self)->&vbsp::Bsp{ fn as_ref(&self)->&vbsp::Bsp{
@ -62,11 +63,21 @@ pub fn read<R:std::io::Read>(mut input:R)->Result<Bsp,ReadError>{
} }
impl Bsp{ impl Bsp{
pub fn new(bsp:vbsp::Bsp)->Self{ pub fn new(bsp:vbsp::Bsp)->Self{
let case_folded_file_names=bsp.pack.clone().into_zip().lock().unwrap().file_names().map(|s|{
(s.to_lowercase(),s.to_owned())
}).collect();
Self{ Self{
bsp, bsp,
case_folded_file_names,
} }
} }
pub fn to_snf(&self,failure_mode:LoadFailureMode,vpk_list:&[vpk::VPK])->Result<strafesnet_common::map::CompleteMap,LoadError>{ pub fn pack_get(&self,name_lowercase:&str)->Result<Option<Vec<u8>>,vbsp::BspError>{
match self.case_folded_file_names.get(name_lowercase){
Some(name_folded)=>self.bsp.pack.get(name_folded),
None=>Ok(None),
}
}
pub fn to_snf(&self,failure_mode:LoadFailureMode,vpk_list:&[Vpk])->Result<strafesnet_common::map::CompleteMap,LoadError>{
let mut texture_deferred_loader=RenderConfigDeferredLoader::new(); let mut texture_deferred_loader=RenderConfigDeferredLoader::new();
let mut mesh_deferred_loader=MeshDeferredLoader::new(); let mut mesh_deferred_loader=MeshDeferredLoader::new();
@ -89,3 +100,27 @@ impl Bsp{
Ok(map) Ok(map)
} }
} }
pub struct Vpk{
vpk:vpk::VPK,
case_folded_file_names:std::collections::HashMap<String,String>,
}
impl AsRef<vpk::VPK> for Vpk{
fn as_ref(&self)->&vpk::VPK{
&self.vpk
}
}
impl Vpk{
pub fn new(vpk:vpk::VPK)->Vpk{
let case_folded_file_names=vpk.tree.keys().map(|s|{
(s.to_lowercase(),s.to_owned())
}).collect();
Vpk{
vpk,
case_folded_file_names,
}
}
pub fn tree_get(&self,name_lowercase:&str)->Option<&vpk::entry::VPKEntry>{
let name_folded=self.case_folded_file_names.get(name_lowercase)?;
self.vpk.tree.get(name_folded)
}
}

@ -3,7 +3,7 @@ use std::{borrow::Cow, io::Read};
use strafesnet_common::model::Mesh; use strafesnet_common::model::Mesh;
use strafesnet_deferred_loader::{loader::Loader,texture::Texture}; use strafesnet_deferred_loader::{loader::Loader,texture::Texture};
use crate::Bsp; use crate::{Bsp,Vpk};
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
@ -76,7 +76,7 @@ impl From<vbsp::BspError> for MeshError{
#[derive(Clone,Copy)] #[derive(Clone,Copy)]
pub struct BspFinder<'bsp,'vpk>{ pub struct BspFinder<'bsp,'vpk>{
pub bsp:&'bsp Bsp, pub bsp:&'bsp Bsp,
pub vpks:&'vpk [vpk::VPK], pub vpks:&'vpk [Vpk],
} }
impl<'bsp,'vpk> BspFinder<'bsp,'vpk>{ impl<'bsp,'vpk> BspFinder<'bsp,'vpk>{
pub fn find<'a>(&self,path:&str)->Result<Option<Cow<'a,[u8]>>,vbsp::BspError> pub fn find<'a>(&self,path:&str)->Result<Option<Cow<'a,[u8]>>,vbsp::BspError>
@ -85,13 +85,13 @@ impl<'bsp,'vpk> BspFinder<'bsp,'vpk>{
'vpk:'a, 'vpk:'a,
{ {
// search bsp // search bsp
if let Some(data)=self.bsp.as_ref().pack.get(path)?{ if let Some(data)=self.bsp.pack_get(path)?{
return Ok(Some(Cow::Owned(data))); return Ok(Some(Cow::Owned(data)));
} }
//search each vpk //search each vpk
for vpk in self.vpks{ for vpk in self.vpks{
if let Some(vpk_entry)=vpk.tree.get(path){ if let Some(vpk_entry)=vpk.tree_get(path){
return Ok(Some(vpk_entry.get()?)); return Ok(Some(vpk_entry.get()?));
} }
} }

@ -228,7 +228,7 @@ enum ExtractTextureError{
#[error("Load VMT error {0:?}")] #[error("Load VMT error {0:?}")]
LoadVMT(#[from]LoadVMTError), LoadVMT(#[from]LoadVMTError),
} }
async fn gimme_them_textures(path:&Path,vpk_list:&[vpk::VPK],send_texture:tokio::sync::mpsc::Sender<(Vec<u8>,String)>)->Result<(),ExtractTextureError>{ async fn gimme_them_textures(path:&Path,vpk_list:&[strafesnet_bsp_loader::Vpk],send_texture:tokio::sync::mpsc::Sender<(Vec<u8>,String)>)->Result<(),ExtractTextureError>{
let bsp=vbsp::Bsp::read(tokio::fs::read(path).await?.as_ref())?; let bsp=vbsp::Bsp::read(tokio::fs::read(path).await?.as_ref())?;
let loader_bsp=strafesnet_bsp_loader::Bsp::new(bsp); let loader_bsp=strafesnet_bsp_loader::Bsp::new(bsp);
let bsp=loader_bsp.as_ref(); let bsp=loader_bsp.as_ref();
@ -323,10 +323,10 @@ async fn convert_texture(texture:Vec<u8>,write_file_name:impl AsRef<Path>)->Resu
Ok(()) Ok(())
} }
async fn read_vpks(vpk_paths:Vec<PathBuf>,thread_limit:usize)->Vec<vpk::VPK>{ async fn read_vpks(vpk_paths:Vec<PathBuf>,thread_limit:usize)->Vec<strafesnet_bsp_loader::Vpk>{
futures::stream::iter(vpk_paths).map(|vpk_path|async{ futures::stream::iter(vpk_paths).map(|vpk_path|async{
// idk why it doesn't want to pass out the errors but this is fatal anyways // idk why it doesn't want to pass out the errors but this is fatal anyways
tokio::task::spawn_blocking(move||vpk::VPK::read(&vpk_path)).await.unwrap().unwrap() tokio::task::spawn_blocking(move||Ok::<_,vpk::Error>(strafesnet_bsp_loader::Vpk::new(vpk::VPK::read(&vpk_path)?))).await.unwrap().unwrap()
}) })
.buffer_unordered(thread_limit) .buffer_unordered(thread_limit)
.collect().await .collect().await
@ -340,11 +340,8 @@ async fn extract_textures(paths:Vec<PathBuf>,vpk_paths:Vec<PathBuf>)->AResult<()
)?; )?;
let thread_limit=std::thread::available_parallelism()?.get(); let thread_limit=std::thread::available_parallelism()?.get();
// load vpk list // load vpk list and leak for static lifetime
let vpk_list=read_vpks(vpk_paths,thread_limit).await; let vpk_list:&[strafesnet_bsp_loader::Vpk]=read_vpks(vpk_paths,thread_limit).await.leak();
// leak vpk_list for static lifetime?
let vpk_list:&[vpk::VPK]=vpk_list.leak();
let (send_texture,mut recv_texture)=tokio::sync::mpsc::channel(thread_limit); let (send_texture,mut recv_texture)=tokio::sync::mpsc::channel(thread_limit);
let mut it=paths.into_iter(); let mut it=paths.into_iter();
@ -414,7 +411,7 @@ impl std::fmt::Display for ConvertError{
} }
impl std::error::Error for ConvertError{} impl std::error::Error for ConvertError{}
async fn convert_to_snf(path:&Path,vpk_list:&[vpk::VPK],output_folder:PathBuf)->AResult<()>{ async fn convert_to_snf(path:&Path,vpk_list:&[strafesnet_bsp_loader::Vpk],output_folder:PathBuf)->AResult<()>{
let entire_file=tokio::fs::read(path).await?; let entire_file=tokio::fs::read(path).await?;
let bsp=strafesnet_bsp_loader::read( let bsp=strafesnet_bsp_loader::read(
@ -437,11 +434,8 @@ async fn source_to_snf(paths:Vec<std::path::PathBuf>,output_folder:PathBuf,vpk_p
let thread_limit=std::thread::available_parallelism()?.get(); let thread_limit=std::thread::available_parallelism()?.get();
// load vpk list // load vpk list and leak for static lifetime
let vpk_list=read_vpks(vpk_paths,thread_limit).await; let vpk_list:&[strafesnet_bsp_loader::Vpk]=read_vpks(vpk_paths,thread_limit).await.leak();
// leak vpk_list for static lifetime?
let vpk_list:&[vpk::VPK]=vpk_list.leak();
let mut it=paths.into_iter(); let mut it=paths.into_iter();
static SEM:tokio::sync::Semaphore=tokio::sync::Semaphore::const_new(0); static SEM:tokio::sync::Semaphore=tokio::sync::Semaphore::const_new(0);