use std::fs;
use std::io::Cursor;
use std::path::Path;
use crate::api::{LodAdt, Obj0Adt, RootAdt, Tex0Adt};
use crate::error::Result;
use crate::merger::merge_split_files;
use crate::split_set::SplitFileSet;
use crate::{ParsedAdt, parse_adt};
#[derive(Debug, Clone)]
pub struct AdtSet {
pub root: RootAdt,
pub texture: Option<Tex0Adt>,
pub object: Option<Obj0Adt>,
pub lod: Option<LodAdt>,
}
impl AdtSet {
pub fn load_from_path(root_path: impl AsRef<Path>) -> Result<Self> {
let root_path = root_path.as_ref();
let file_set = SplitFileSet::discover(root_path);
let root_data = fs::read(&file_set.root)?;
let mut cursor = Cursor::new(root_data);
let root = match parse_adt(&mut cursor)? {
ParsedAdt::Root(r) => *r,
_ => {
return Err(crate::error::AdtError::ChunkParseError {
chunk: crate::chunk_id::ChunkId::MVER,
offset: 0,
details: "Expected root ADT file but got different file type".to_string(),
});
}
};
let texture = if let Some(tex_path) = &file_set.tex0 {
let tex_data = fs::read(tex_path)?;
let mut cursor = Cursor::new(tex_data);
match parse_adt(&mut cursor)? {
ParsedAdt::Tex0(t) => Some(t),
_ => None,
}
} else {
None
};
let object = if let Some(obj_path) = &file_set.obj0 {
let obj_data = fs::read(obj_path)?;
let mut cursor = Cursor::new(obj_data);
match parse_adt(&mut cursor)? {
ParsedAdt::Obj0(o) => Some(o),
_ => None,
}
} else {
None
};
let lod = if let Some(lod_path) = &file_set.lod {
let lod_data = fs::read(lod_path)?;
let mut cursor = Cursor::new(lod_data);
match parse_adt(&mut cursor)? {
ParsedAdt::Lod(l) => Some(l),
_ => None,
}
} else {
None
};
Ok(AdtSet {
root,
texture,
object,
lod,
})
}
pub fn merge(self) -> Result<RootAdt> {
merge_split_files(self.root, self.texture, self.object)
}
pub fn is_complete(&self) -> bool {
self.texture.is_some() && self.object.is_some()
}
pub fn version(&self) -> crate::version::AdtVersion {
self.root.version
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chunks::McnkChunk;
use crate::version::AdtVersion;
fn create_test_mcnk() -> McnkChunk {
unsafe { std::mem::zeroed() }
}
fn create_test_root() -> RootAdt {
RootAdt {
version: AdtVersion::Cataclysm,
mhdr: Default::default(),
mcin: Default::default(),
textures: vec![],
models: vec![],
model_indices: vec![],
wmos: vec![],
wmo_indices: vec![],
doodad_placements: vec![],
wmo_placements: vec![],
mcnk_chunks: vec![create_test_mcnk(), create_test_mcnk()],
flight_bounds: None,
water_data: None,
texture_flags: None,
texture_amplifier: None,
texture_params: None,
blend_mesh_headers: None,
blend_mesh_bounds: None,
blend_mesh_vertices: None,
blend_mesh_indices: None,
}
}
fn create_test_tex() -> Tex0Adt {
Tex0Adt {
version: AdtVersion::Cataclysm,
textures: vec!["texture1.blp".to_string()],
texture_params: None,
mcnk_textures: vec![],
}
}
fn create_test_obj() -> Obj0Adt {
Obj0Adt {
version: AdtVersion::Cataclysm,
models: vec!["model1.m2".to_string()],
model_indices: vec![0],
wmos: vec![],
wmo_indices: vec![],
doodad_placements: vec![],
wmo_placements: vec![],
mcnk_objects: vec![],
}
}
#[test]
fn test_adt_set_complete() {
let adt_set = AdtSet {
root: create_test_root(),
texture: Some(create_test_tex()),
object: Some(create_test_obj()),
lod: None,
};
assert!(adt_set.is_complete());
assert_eq!(adt_set.version(), AdtVersion::Cataclysm);
}
#[test]
fn test_adt_set_incomplete() {
let adt_set = AdtSet {
root: create_test_root(),
texture: Some(create_test_tex()),
object: None,
lod: None,
};
assert!(!adt_set.is_complete());
}
#[test]
fn test_adt_set_merge() {
let adt_set = AdtSet {
root: create_test_root(),
texture: Some(create_test_tex()),
object: Some(create_test_obj()),
lod: None,
};
let result = adt_set.merge();
assert!(result.is_ok());
let merged = result.unwrap();
assert_eq!(merged.textures.len(), 1);
assert_eq!(merged.models.len(), 1);
}
#[test]
fn test_adt_set_merge_no_optional() {
let adt_set = AdtSet {
root: create_test_root(),
texture: None,
object: None,
lod: None,
};
let result = adt_set.merge();
assert!(result.is_ok());
let merged = result.unwrap();
assert_eq!(merged.textures.len(), 0);
assert_eq!(merged.models.len(), 0);
}
}