WIP: Implement texture files #191

Draft
lucas wants to merge 14 commits from feat/textures into master
Showing only changes of commit 126d3c743d - Show all commits

View file

@ -3,19 +3,28 @@ use std::path::PathBuf;
use clap::{value_parser, Arg, ArgMatches, Command}; use clap::{value_parser, Arg, ArgMatches, Command};
use color_eyre::eyre::{self, Context, Result}; use color_eyre::eyre::{self, Context, Result};
use color_eyre::Help; use color_eyre::Help;
use sdk::murmur::IdString64;
use sdk::Bundle; use sdk::Bundle;
use tokio::fs::{self, File}; use tokio::fs::{self, File};
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
pub(crate) fn command_definition() -> Command { pub(crate) fn command_definition() -> Command {
Command::new("inject") Command::new("inject")
.about("Inject a file into a bundle.") .about("Inject a file into a bundle.\n\
Raw binary data can be used to directly replace the file's variant data blob without affecting the metadata.\n\
Alternatively, a compiler format may be specified, and a complete bundle file is created.")
.arg( .arg(
Arg::new("replace") Arg::new("replace")
.help("The name of a file in the bundle whos content should be replaced.") .help("The name of a file in the bundle whose content should be replaced.")
.short('r') .short('r')
.long("replace"), .long("replace"),
) )
.arg(
Arg::new("compile")
.help("Compile the file with the given data format before injecting.")
.long("compile")
.short('c')
)
.arg( .arg(
Arg::new("output") Arg::new("output")
.help( .help(
@ -58,55 +67,60 @@ pub(crate) async fn run(ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
Bundle::from_binary(&ctx, name, binary).wrap_err("Failed to open bundle file")? Bundle::from_binary(&ctx, name, binary).wrap_err("Failed to open bundle file")?
}; };
if let Some(name) = matches.get_one::<String>("replace") { let name = match matches.get_one::<String>("replace") {
let mut file = File::open(&file_path) Some(name) => match u64::from_str_radix(name, 16) {
Ok(id) => IdString64::from(id),
Err(_) => IdString64::String(name.clone()),
},
None => eyre::bail!("Currently, only the '--replace' operation is supported."),
};
let mut file = File::open(&file_path)
.await
.wrap_err_with(|| format!("Failed to open '{}'", file_path.display()))?;
if let Some(variant) = bundle
.files_mut()
.filter(|file| file.matches_name(name.clone()))
// TODO: Handle file variants
.find_map(|file| file.variants_mut().next())
{
let mut data = Vec::new();
file.read_to_end(&mut data)
.await .await
.wrap_err_with(|| format!("Failed to open '{}'", file_path.display()))?; .wrap_err("Failed to read input file")?;
variant.set_data(data);
if let Some(variant) = bundle
.files_mut()
.filter(|file| file.matches_name(name.clone()))
// TODO: Handle file variants
.find_map(|file| file.variants_mut().next())
{
let mut data = Vec::new();
file.read_to_end(&mut data)
.await
.wrap_err("Failed to read input file")?;
variant.set_data(data);
} else {
let err = eyre::eyre!("No file '{}' in this bundle.", name)
.with_suggestion(|| {
format!(
"Run '{} bundle list {}' to list the files in this bundle.",
clap::crate_name!(),
bundle_path.display()
)
})
.with_suggestion(|| {
format!(
"Use '{} bundle inject --add {} {} {}' to add it as a new file",
clap::crate_name!(),
name,
bundle_path.display(),
file_path.display()
)
});
return Err(err);
}
let out_path = matches.get_one::<PathBuf>("output").unwrap_or(bundle_path);
let data = bundle
.to_binary()
.wrap_err("Failed to write changed bundle to output")?;
fs::write(out_path, &data)
.await
.wrap_err("Failed to write data to output file")?;
Ok(())
} else { } else {
eyre::bail!("Currently, only the '--replace' operation is supported."); let err =
eyre::eyre!("No file '{}' in this bundle.", name.display()).with_suggestion(|| {
format!(
"Run '{} bundle list {}' to list the files in this bundle.",
clap::crate_name!(),
bundle_path.display()
)
// Not yet supported.
// })
// .with_suggestion(|| {
// format!(
// "Use '{} bundle inject --add {} {} {}' to add it as a new file",
// clap::crate_name!(),
// name.display(),
// bundle_path.display(),
// file_path.display()
// )
});
return Err(err);
} }
let out_path = matches.get_one::<PathBuf>("output").unwrap_or(bundle_path);
let data = bundle
.to_binary()
.wrap_err("Failed to write changed bundle to output")?;
fs::write(out_path, &data)
.await
.wrap_err("Failed to write data to output file")?;
Ok(())
} }