use std::path::{Path, PathBuf};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SplitFileSet {
pub root: PathBuf,
pub tex0: Option<PathBuf>,
pub tex1: Option<PathBuf>,
pub obj0: Option<PathBuf>,
pub obj1: Option<PathBuf>,
pub lod: Option<PathBuf>,
}
impl SplitFileSet {
pub fn discover(root_path: impl AsRef<Path>) -> Self {
let root = root_path.as_ref().to_path_buf();
let parent = root.parent().expect("Root path must have parent directory");
let stem = root
.file_stem()
.and_then(|s| s.to_str())
.expect("Root path must have file stem");
Self {
root: root.clone(),
tex0: Some(parent.join(format!("{}_tex0.adt", stem))),
tex1: Some(parent.join(format!("{}_tex1.adt", stem))),
obj0: Some(parent.join(format!("{}_obj0.adt", stem))),
obj1: Some(parent.join(format!("{}_obj1.adt", stem))),
lod: Some(parent.join(format!("{}_lod.adt", stem))),
}
}
pub fn verify_existence(&self) -> SplitFilePresence {
SplitFilePresence {
has_root: self.root.exists(),
has_tex0: self.tex0.as_ref().is_some_and(|p| p.exists()),
has_tex1: self.tex1.as_ref().is_some_and(|p| p.exists()),
has_obj0: self.obj0.as_ref().is_some_and(|p| p.exists()),
has_obj1: self.obj1.as_ref().is_some_and(|p| p.exists()),
has_lod: self.lod.as_ref().is_some_and(|p| p.exists()),
}
}
pub fn present_files(&self) -> Vec<&PathBuf> {
let mut files = vec![&self.root];
if let Some(ref tex0) = self.tex0 {
files.push(tex0);
}
if let Some(ref tex1) = self.tex1 {
files.push(tex1);
}
if let Some(ref obj0) = self.obj0 {
files.push(obj0);
}
if let Some(ref obj1) = self.obj1 {
files.push(obj1);
}
if let Some(ref lod) = self.lod {
files.push(lod);
}
files
}
pub fn is_complete_cataclysm_set(&self) -> bool {
let presence = self.verify_existence();
presence.has_root && presence.has_tex0 && presence.has_obj0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SplitFilePresence {
pub has_root: bool,
pub has_tex0: bool,
pub has_tex1: bool,
pub has_obj0: bool,
pub has_obj1: bool,
pub has_lod: bool,
}
impl SplitFilePresence {
#[inline]
pub const fn is_complete_cataclysm_set(&self) -> bool {
self.has_root && self.has_tex0 && self.has_obj0
}
#[inline]
pub const fn is_monolithic(&self) -> bool {
self.has_root
&& !self.has_tex0
&& !self.has_tex1
&& !self.has_obj0
&& !self.has_obj1
&& !self.has_lod
}
#[inline]
pub const fn has_split_files(&self) -> bool {
self.has_tex0 || self.has_tex1 || self.has_obj0 || self.has_obj1 || self.has_lod
}
pub const fn count(&self) -> usize {
let mut count = 0;
if self.has_root {
count += 1;
}
if self.has_tex0 {
count += 1;
}
if self.has_tex1 {
count += 1;
}
if self.has_obj0 {
count += 1;
}
if self.has_obj1 {
count += 1;
}
if self.has_lod {
count += 1;
}
count
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_discover_split_files() {
let root = PathBuf::from("World/Maps/Azeroth/Azeroth_30_30.adt");
let set = SplitFileSet::discover(&root);
assert_eq!(
set.root,
PathBuf::from("World/Maps/Azeroth/Azeroth_30_30.adt")
);
assert_eq!(
set.tex0,
Some(PathBuf::from("World/Maps/Azeroth/Azeroth_30_30_tex0.adt"))
);
assert_eq!(
set.tex1,
Some(PathBuf::from("World/Maps/Azeroth/Azeroth_30_30_tex1.adt"))
);
assert_eq!(
set.obj0,
Some(PathBuf::from("World/Maps/Azeroth/Azeroth_30_30_obj0.adt"))
);
assert_eq!(
set.obj1,
Some(PathBuf::from("World/Maps/Azeroth/Azeroth_30_30_obj1.adt"))
);
assert_eq!(
set.lod,
Some(PathBuf::from("World/Maps/Azeroth/Azeroth_30_30_lod.adt"))
);
}
#[test]
fn test_discover_without_directory() {
let root = PathBuf::from("Azeroth_30_30.adt");
let set = SplitFileSet::discover(&root);
assert_eq!(set.root, PathBuf::from("Azeroth_30_30.adt"));
assert_eq!(set.tex0, Some(PathBuf::from("Azeroth_30_30_tex0.adt")));
assert_eq!(set.obj0, Some(PathBuf::from("Azeroth_30_30_obj0.adt")));
}
#[test]
fn test_present_files() {
let set = SplitFileSet::discover("Azeroth_30_30.adt");
let files = set.present_files();
assert_eq!(files.len(), 6); }
#[test]
fn test_split_file_presence_is_complete() {
let complete = SplitFilePresence {
has_root: true,
has_tex0: true,
has_tex1: false,
has_obj0: true,
has_obj1: false,
has_lod: false,
};
assert!(complete.is_complete_cataclysm_set());
let incomplete = SplitFilePresence {
has_root: true,
has_tex0: false, has_tex1: false,
has_obj0: true,
has_obj1: false,
has_lod: false,
};
assert!(!incomplete.is_complete_cataclysm_set());
}
#[test]
fn test_split_file_presence_is_monolithic() {
let monolithic = SplitFilePresence {
has_root: true,
has_tex0: false,
has_tex1: false,
has_obj0: false,
has_obj1: false,
has_lod: false,
};
assert!(monolithic.is_monolithic());
let split = SplitFilePresence {
has_root: true,
has_tex0: true,
has_tex1: false,
has_obj0: true,
has_obj1: false,
has_lod: false,
};
assert!(!split.is_monolithic());
}
#[test]
fn test_split_file_presence_count() {
let presence = SplitFilePresence {
has_root: true,
has_tex0: true,
has_tex1: false,
has_obj0: true,
has_obj1: false,
has_lod: false,
};
assert_eq!(presence.count(), 3);
let all = SplitFilePresence {
has_root: true,
has_tex0: true,
has_tex1: true,
has_obj0: true,
has_obj1: true,
has_lod: true,
};
assert_eq!(all.count(), 6);
}
}