use std::path::Path;
use crate::archive::War3MapW3x;
use crate::error::Result;
use crate::formats::imp::War3MapImp;
use crate::formats::mmp::{MinimapIcon, War3MapMmp};
use crate::formats::w3i::War3MapW3i;
use crate::formats::wts::{trigstr_id, War3MapWts};
use crate::model::{
header::War3MapHeader, image::War3Image, image::War3ImageData, snapshot::MapSnapshot,
};
const UNRESOLVED_TRIGSTR: &str = "Unknown";
pub struct War3MapMetadata {
pub header: War3MapHeader,
pub map_info: Option<War3MapW3i>,
pub imp: Option<War3MapImp>,
pub wts: Option<War3MapWts>,
pub images: Vec<War3Image>,
pub minimap_icons: Option<War3MapMmp>,
pub files: Option<Vec<String>>,
}
impl War3MapMetadata {
pub fn parse(buffer: &[u8]) -> Result<Self> {
let mut w3x = War3MapW3x::from_buffer(buffer)?;
let mut images = Vec::new();
if let Ok(minimap) = w3x.read_minimap() {
images.push(minimap);
}
if let Ok(preview) = w3x.read_preview() {
images.push(preview);
}
let mut files = w3x.files.clone();
if let Some(list) = &mut files {
list.sort();
}
Ok(Self {
header: w3x.header.clone(),
map_info: w3x.read_map_info().ok(),
imp: w3x.read_imports().ok(),
wts: w3x.read_string_table().ok(),
images,
minimap_icons: w3x.read_minimap_icons().ok(),
files,
})
}
pub fn parse_snapshot(buffer: &[u8]) -> Result<MapSnapshot> {
let mut metadata = Self::parse(buffer)?;
metadata.resolve_trigger_strings();
metadata.snapshot()
}
pub fn resolve_trigger_strings(&mut self) {
let (Some(map_info), Some(wts)) = (&mut self.map_info, &self.wts) else {
return;
};
map_info.visit_strings(|s| {
if let Some(id) = trigstr_id(s) {
*s = wts.get(id).unwrap_or(UNRESOLVED_TRIGSTR).to_string();
}
});
}
pub fn snapshot(&self) -> Result<MapSnapshot> {
let images = self
.images
.iter()
.map(War3ImageData::try_from)
.collect::<Result<Vec<_>>>()?;
let minimap_icons: Vec<MinimapIcon> = self
.minimap_icons
.as_ref()
.map(|m| m.icons.clone())
.unwrap_or_default();
Ok(MapSnapshot {
header: self.header.clone(),
map_info: self.map_info.clone(),
images,
minimap_icons,
imports: self.imp.as_ref().map(War3MapImp::entries_sorted),
strings: self.wts.as_ref().map(War3MapWts::entries_sorted),
files: self.files.clone(),
parse_ms: None,
})
}
pub fn save(&self, out_dir: impl AsRef<Path>) -> Result<()> {
let out_dir = out_dir.as_ref();
self.snapshot()?.save(out_dir)?;
for (index, image) in self.images.iter().enumerate() {
let image_path = out_dir.join(format!("{}_{}.png", image.filename, index));
image.data.save(image_path)?;
}
Ok(())
}
}