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{
bsp:vbsp::Bsp,
case_folded_file_names:std::collections::HashMap<String,String>,
}
impl AsRef<vbsp::Bsp> for 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{
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{
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 mesh_deferred_loader=MeshDeferredLoader::new();
@ -89,3 +100,27 @@ impl Bsp{
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_deferred_loader::{loader::Loader,texture::Texture};
use crate::Bsp;
use crate::{Bsp,Vpk};
#[allow(dead_code)]
#[derive(Debug)]
@ -76,7 +76,7 @@ impl From<vbsp::BspError> for MeshError{
#[derive(Clone,Copy)]
pub struct BspFinder<'bsp,'vpk>{
pub bsp:&'bsp Bsp,
pub vpks:&'vpk [vpk::VPK],
pub vpks:&'vpk [Vpk],
}
impl<'bsp,'vpk> BspFinder<'bsp,'vpk>{
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,
{
// 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)));
}
//search each vpk
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()?));
}
}

@ -228,7 +228,7 @@ enum ExtractTextureError{
#[error("Load VMT error {0:?}")]
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 loader_bsp=strafesnet_bsp_loader::Bsp::new(bsp);
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(())
}
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{
// 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)
.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();
// load vpk list
let vpk_list=read_vpks(vpk_paths,thread_limit).await;
// leak vpk_list for static lifetime?
let vpk_list:&[vpk::VPK]=vpk_list.leak();
// load vpk list and leak for static lifetime
let vpk_list:&[strafesnet_bsp_loader::Vpk]=read_vpks(vpk_paths,thread_limit).await.leak();
let (send_texture,mut recv_texture)=tokio::sync::mpsc::channel(thread_limit);
let mut it=paths.into_iter();
@ -414,7 +411,7 @@ impl std::fmt::Display 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 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();
// load vpk list
let vpk_list=read_vpks(vpk_paths,thread_limit).await;
// leak vpk_list for static lifetime?
let vpk_list:&[vpk::VPK]=vpk_list.leak();
// load vpk list and leak for static lifetime
let vpk_list:&[strafesnet_bsp_loader::Vpk]=read_vpks(vpk_paths,thread_limit).await.leak();
let mut it=paths.into_iter();
static SEM:tokio::sync::Semaphore=tokio::sync::Semaphore::const_new(0);