source to snf

This commit is contained in:
Quaternions 2024-07-31 11:51:18 -07:00
parent ed9701981d
commit 451f3ccecb
3 changed files with 101 additions and 2 deletions

13
Cargo.lock generated
View File

@ -807,6 +807,7 @@ dependencies = [
"rbx_dom_weak 2.8.0", "rbx_dom_weak 2.8.0",
"rbx_reflection_database 0.2.11+roblox-634", "rbx_reflection_database 0.2.11+roblox-634",
"rbx_xml 0.13.4", "rbx_xml 0.13.4",
"strafesnet_bsp_loader",
"strafesnet_deferred_loader", "strafesnet_deferred_loader",
"strafesnet_rbx_loader", "strafesnet_rbx_loader",
"strafesnet_snf", "strafesnet_snf",
@ -1391,6 +1392,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strafesnet_bsp_loader"
version = "0.1.3"
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
checksum = "6d4af68c422b5f57febbaa218f44ba02d413fd25e84afff9e45e557a8caee2ce"
dependencies = [
"glam",
"strafesnet_common",
"vbsp",
"vmdl",
]
[[package]] [[package]]
name = "strafesnet_common" name = "strafesnet_common"
version = "0.2.0" version = "0.2.0"

View File

@ -16,6 +16,7 @@ rbx_binary = "0.7.1"
rbx_dom_weak = "2.5.0" rbx_dom_weak = "2.5.0"
rbx_reflection_database = "0.2.7" rbx_reflection_database = "0.2.7"
rbx_xml = "0.13.1" rbx_xml = "0.13.1"
strafesnet_bsp_loader = { version = "0.1.3", registry = "strafesnet" }
strafesnet_deferred_loader = { version = "0.3.1", features = ["legacy"], registry = "strafesnet" } strafesnet_deferred_loader = { version = "0.3.1", features = ["legacy"], registry = "strafesnet" }
strafesnet_rbx_loader = { version = "0.3.1", registry = "strafesnet" } strafesnet_rbx_loader = { version = "0.3.1", registry = "strafesnet" }
strafesnet_snf = { version = "0.1.0", registry = "strafesnet" } strafesnet_snf = { version = "0.1.0", registry = "strafesnet" }

View File

@ -14,6 +14,7 @@ struct Cli {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Commands { enum Commands {
RobloxToSNF(RobloxToSNFSubcommand), RobloxToSNF(RobloxToSNFSubcommand),
SourceToSNF(SourceToSNFSubcommand),
DownloadTextures(DownloadTexturesSubcommand), DownloadTextures(DownloadTexturesSubcommand),
ExtractTextures(ExtractTexturesSubcommand), ExtractTextures(ExtractTexturesSubcommand),
ConvertTextures(ConvertTexturesSubcommand), ConvertTextures(ConvertTexturesSubcommand),
@ -31,6 +32,13 @@ struct RobloxToSNFSubcommand {
input_files:Vec<PathBuf>, input_files:Vec<PathBuf>,
} }
#[derive(Args)] #[derive(Args)]
struct SourceToSNFSubcommand {
#[arg(long)]
output_folder:PathBuf,
#[arg(required=true)]
input_files:Vec<PathBuf>,
}
#[derive(Args)]
struct DownloadTexturesSubcommand { struct DownloadTexturesSubcommand {
#[arg(long,required=true)] #[arg(long,required=true)]
roblox_files:Vec<PathBuf> roblox_files:Vec<PathBuf>
@ -67,7 +75,8 @@ struct WriteAttributesSubcommand {
fn main() -> AResult<()> { fn main() -> AResult<()> {
let cli = Cli::parse(); let cli = Cli::parse();
match cli.command { match cli.command {
Commands::RobloxToSNF(subcommand)=>convert_to_snf(subcommand.input_files,subcommand.output_folder), Commands::RobloxToSNF(subcommand)=>roblox_to_snf(subcommand.input_files,subcommand.output_folder),
Commands::SourceToSNF(subcommand)=>source_to_snf(subcommand.input_files,subcommand.output_folder),
Commands::DownloadTextures(subcommand)=>download_textures(subcommand.roblox_files), Commands::DownloadTextures(subcommand)=>download_textures(subcommand.roblox_files),
Commands::ExtractTextures(subcommand)=>extract_textures(vec![subcommand.bsp_file],subcommand.vpk_dir_files), Commands::ExtractTextures(subcommand)=>extract_textures(vec![subcommand.bsp_file],subcommand.vpk_dir_files),
Commands::VPKContents(subcommand)=>vpk_contents(subcommand.input_file), Commands::VPKContents(subcommand)=>vpk_contents(subcommand.input_file),
@ -646,6 +655,7 @@ enum ConvertError{
IO(std::io::Error), IO(std::io::Error),
SNFMap(strafesnet_snf::map::Error), SNFMap(strafesnet_snf::map::Error),
RbxLoader(strafesnet_rbx_loader::ReadError), RbxLoader(strafesnet_rbx_loader::ReadError),
BspLoader(strafesnet_bsp_loader::ReadError),
} }
impl std::fmt::Display for ConvertError{ impl std::fmt::Display for ConvertError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@ -656,7 +666,7 @@ impl std::error::Error for ConvertError{}
type MapThread=std::thread::JoinHandle<Result<(),ConvertError>>; type MapThread=std::thread::JoinHandle<Result<(),ConvertError>>;
fn convert_to_snf(pathlist:Vec<std::path::PathBuf>,output_folder:PathBuf)->AResult<()>{ fn roblox_to_snf(pathlist:Vec<std::path::PathBuf>,output_folder:PathBuf)->AResult<()>{
let n_paths=pathlist.len(); let n_paths=pathlist.len();
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let mut threads:std::collections::VecDeque<MapThread>=std::collections::VecDeque::new(); let mut threads:std::collections::VecDeque<MapThread>=std::collections::VecDeque::new();
@ -724,3 +734,78 @@ fn convert_to_snf(pathlist:Vec<std::path::PathBuf>,output_folder:PathBuf)->AResu
println!("{:?}", start.elapsed()); println!("{:?}", start.elapsed());
Ok(()) Ok(())
} }
fn source_to_snf(pathlist:Vec<std::path::PathBuf>,output_folder:PathBuf)->AResult<()>{
let n_paths=pathlist.len();
let start = std::time::Instant::now();
let mut threads:std::collections::VecDeque<MapThread>=std::collections::VecDeque::new();
let mut i=0;
let mut join_thread=|thread:MapThread|{
i+=1;
if let Err(e)=thread.join(){
println!("thread error: {:?}",e);
}else{
println!("{}/{}",i,n_paths);
}
};
for path in pathlist{
if 32<=threads.len(){
join_thread(threads.pop_front().unwrap());
}
let output_folder=output_folder.clone();
threads.push_back(std::thread::spawn(move ||{
let bsp=strafesnet_bsp_loader::read(
std::fs::File::open(path.as_path())
.map_err(ConvertError::IO)?
).map_err(ConvertError::BspLoader)?;
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(ConvertError::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,
})
),
);
let mut dest=output_folder.clone();
dest.push(path.file_stem().unwrap());
dest.set_extension("snfm");
let file=std::fs::File::create(dest).map_err(ConvertError::IO)?;
strafesnet_snf::map::write_map(file,map).map_err(ConvertError::SNFMap)?;
Ok(())
}));
}
for thread in threads{
join_thread(thread);
}
println!("{:?}", start.elapsed());
Ok(())
}