This commit is contained in:
Quaternions 2025-02-03 14:05:39 -08:00
parent e188105da1
commit fc90a986e5

@ -21,13 +21,15 @@ pub struct SourceToSNFSubcommand {
output_folder:PathBuf, output_folder:PathBuf,
#[arg(required=true)] #[arg(required=true)]
input_files:Vec<PathBuf>, input_files:Vec<PathBuf>,
#[arg(long)]
vpk_dir_files:Vec<PathBuf>,
} }
#[derive(Args)] #[derive(Args)]
pub struct ExtractTexturesSubcommand{ pub struct ExtractTexturesSubcommand{
#[arg(required=true)] #[arg(required=true)]
bsp_files:Vec<PathBuf>, bsp_files:Vec<PathBuf>,
#[arg(long)] #[arg(long)]
vpk_dir_file:Vec<PathBuf>, vpk_dir_files:Vec<PathBuf>,
} }
#[derive(Args)] #[derive(Args)]
pub struct VPKContentsSubcommand { pub struct VPKContentsSubcommand {
@ -43,8 +45,8 @@ pub struct BSPContentsSubcommand {
impl Commands{ impl Commands{
pub async fn run(self)->AResult<()>{ pub async fn run(self)->AResult<()>{
match self{ match self{
Commands::SourceToSNF(subcommand)=>source_to_snf(subcommand.input_files,subcommand.output_folder).await, Commands::SourceToSNF(subcommand)=>source_to_snf(subcommand.input_files,subcommand.output_folder,subcommand.vpk_dir_files).await,
Commands::ExtractTextures(subcommand)=>extract_textures(subcommand.bsp_files,subcommand.vpk_dir_file).await, Commands::ExtractTextures(subcommand)=>extract_textures(subcommand.bsp_files,subcommand.vpk_dir_files).await,
Commands::VPKContents(subcommand)=>vpk_contents(subcommand.input_file), Commands::VPKContents(subcommand)=>vpk_contents(subcommand.input_file),
Commands::BSPContents(subcommand)=>bsp_contents(subcommand.input_file), Commands::BSPContents(subcommand)=>bsp_contents(subcommand.input_file),
} }
@ -280,6 +282,15 @@ 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>{
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()
})
.buffer_unordered(thread_limit)
.collect().await
}
async fn extract_textures(paths:Vec<PathBuf>,vpk_paths:Vec<PathBuf>)->AResult<()>{ async fn extract_textures(paths:Vec<PathBuf>,vpk_paths:Vec<PathBuf>)->AResult<()>{
tokio::try_join!( tokio::try_join!(
tokio::fs::create_dir_all("extracted_textures"), tokio::fs::create_dir_all("extracted_textures"),
@ -289,15 +300,10 @@ 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
let vpk_list=futures::stream::iter(vpk_paths).map(|vpk_path|async{ let vpk_list=read_vpks(vpk_paths,thread_limit).await;
// 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()
})
.buffer_unordered(thread_limit)
.collect::<Vec<vpk::VPK>>().await;
// leak vpk_list for static lifetime? // leak vpk_list for static lifetime?
let vpk_list=vpk_list.leak(); 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();
@ -378,10 +384,17 @@ async fn convert_to_snf(path:&Path,vpk_list:&[vpk::VPK],output_folder:PathBuf)->
Ok(()) Ok(())
} }
async fn source_to_snf(paths:Vec<std::path::PathBuf>,output_folder:PathBuf)->AResult<()>{ async fn source_to_snf(paths:Vec<std::path::PathBuf>,output_folder:PathBuf,vpk_paths:Vec<PathBuf>)->AResult<()>{
let start=std::time::Instant::now(); let start=std::time::Instant::now();
let thread_limit=std::thread::available_parallelism()?.get(); 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();
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);
SEM.add_permits(thread_limit); SEM.add_permits(thread_limit);
@ -389,7 +402,7 @@ async fn source_to_snf(paths:Vec<std::path::PathBuf>,output_folder:PathBuf)->ARe
while let (Ok(permit),Some(path))=(SEM.acquire().await,it.next()){ while let (Ok(permit),Some(path))=(SEM.acquire().await,it.next()){
let output_folder=output_folder.clone(); let output_folder=output_folder.clone();
tokio::spawn(async move{ tokio::spawn(async move{
let result=convert_to_snf(path.as_path(),output_folder).await; let result=convert_to_snf(path.as_path(),vpk_list,output_folder).await;
drop(permit); drop(permit);
match result{ match result{
Ok(())=>(), Ok(())=>(),