use std::io::Read;
use std::path::Path;
use rootcause::prelude::*;
use wowsunpack::data::Version;
use wowsunpack::game_data;
pub fn detect_version_for_build(data_dir: &Path, build: u32) -> Result<String, Report> {
let build_dir = data_dir.join("builds").join(build.to_string());
detect_version_at_path(&build_dir, build)
}
pub fn detect_version_at_path(game_dir: &Path, build: u32) -> Result<String, Report> {
let vfs = game_data::build_game_vfs_for_build(game_dir, build)
.attach_with(|| format!("Failed to build VFS for build {build} at {}", game_dir.display()))?;
let account_def_path = "scripts/entity_defs/Account.def";
let file = vfs
.join(account_def_path)
.and_then(|p| p.open_file())
.map_err(|e| rootcause::report!("Failed to open {account_def_path} in VFS for build {build}: {e}"))?;
let mut content = String::new();
std::io::BufReader::new(file).read_to_string(&mut content).attach_with(|| "Failed to read Account.def")?;
let parsed = Version::from_account_def(&content)
.ok_or_else(|| rootcause::report!("Failed to parse version from Account.def"))?;
Ok(format!("{}.{}.{}", parsed.major, parsed.minor, parsed.patch))
}
pub fn detect_all_versions(scan_path: &Path) -> Result<Vec<(u32, String)>, Report> {
if !scan_path.exists() {
return Ok(Vec::new());
}
let mut results = Vec::new();
let entries = std::fs::read_dir(scan_path).attach_with(|| format!("Failed to read {}", scan_path.display()))?;
for entry in entries {
let entry: std::fs::DirEntry = entry?;
if !entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
continue;
}
let dir_name = entry.file_name();
let Some(name_str) = dir_name.to_str() else {
continue;
};
let Ok(build) = name_str.parse::<u32>() else {
continue;
};
let build_path = entry.path();
match detect_version_at_path(&build_path, build) {
Ok(version) => results.push((build, version)),
Err(e) => {
match game_data::list_available_builds(&build_path) {
Ok(sub_builds) => {
for sub_build in sub_builds {
match detect_version_at_path(&build_path, sub_build) {
Ok(version) => results.push((sub_build, version)),
Err(e) => {
eprintln!(
"Warning: could not detect version for build {sub_build} at {}: {e}",
build_path.display()
);
}
}
}
}
Err(_) => {
eprintln!("Warning: could not detect version for build {build}: {e}");
}
}
}
}
}
results.sort_by_key(|(build, _)| *build);
Ok(results)
}