use std::fmt;
use std::path::PathBuf;
use crate::prelude::*;
use crate::util::bench::Stopwatch;
use crate::wad::chunk::ChunkName;
use crate::wad::elem::animation_curve::AnimationCurves;
use crate::wad::elem::audio::Audios;
use crate::wad::elem::audio_group::AudioGroups;
use crate::wad::elem::background::Tilesets;
use crate::wad::elem::code::Codes;
use crate::wad::elem::data_file::DataFiles;
use crate::wad::elem::embedded_image::EmbeddedImages;
use crate::wad::elem::extension::Extensions;
use crate::wad::elem::feature_flag::FeatureFlags;
use crate::wad::elem::filter_effect::FilterEffects;
use crate::wad::elem::font::Fonts;
use crate::wad::elem::function::Functions;
use crate::wad::elem::game_end::GameEndScripts;
use crate::wad::elem::game_object::GameObjects;
use crate::wad::elem::general_info::GeneralInfo;
use crate::wad::elem::global_init::GlobalInitScripts;
use crate::wad::elem::language::LanguageInfo;
use crate::wad::elem::options::Options;
use crate::wad::elem::particle_emitter::ParticleEmitters;
use crate::wad::elem::particle_system::ParticleSystems;
use crate::wad::elem::path::Paths;
use crate::wad::elem::room::Rooms;
use crate::wad::elem::script::Scripts;
use crate::wad::elem::sequence::Sequences;
use crate::wad::elem::shader::Shaders;
use crate::wad::elem::sound::Sounds;
use crate::wad::elem::sprite::Sprites;
use crate::wad::elem::string::Strings;
use crate::wad::elem::tag::Tags;
use crate::wad::elem::texture_group_info::TextureGroupInfos;
use crate::wad::elem::texture_page::TexturePages;
use crate::wad::elem::texture_page_item::TexturePageItems;
use crate::wad::elem::timeline::Timelines;
use crate::wad::elem::ui_node::UINodes;
use crate::wad::elem::validate_names;
use crate::wad::elem::variable::Variables;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Endianness {
#[default]
Little,
Big,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct Metadata {
pub location: Option<PathBuf>,
pub chunk_padding: u32,
pub endianness: Endianness,
pub original_data_size: u32,
pub(crate) chunk_order: Vec<ChunkName>,
}
impl Default for Metadata {
fn default() -> Self {
Self {
location: None,
chunk_padding: 16,
endianness: Endianness::Little,
original_data_size: 0,
chunk_order: Vec::new(),
}
}
}
#[derive(Clone, Default)]
pub struct GMData {
pub meta: Metadata,
pub animation_curves: AnimationCurves, pub audio_groups: AudioGroups, pub audios: Audios, pub codes: Codes, pub(crate) data_files: DataFiles, pub embedded_images: EmbeddedImages, pub extensions: Extensions, pub feature_flags: FeatureFlags, pub filter_effects: FilterEffects, pub fonts: Fonts, pub functions: Functions, pub game_end_scripts: GameEndScripts, pub game_objects: GameObjects, pub general_info: GeneralInfo, pub global_init_scripts: GlobalInitScripts, pub language_info: LanguageInfo, pub options: Options, pub particle_emitters: ParticleEmitters, pub particle_systems: ParticleSystems, pub paths: Paths, pub rooms: Rooms, pub ui_nodes: UINodes, pub scripts: Scripts, pub sequences: Sequences, pub shaders: Shaders, pub sounds: Sounds, pub sprites: Sprites, pub strings: Strings, pub tags: Tags, pub texture_group_infos: TextureGroupInfos, pub texture_page_items: TexturePageItems, pub texture_pages: TexturePages, pub tilesets: Tilesets, pub timelines: Timelines, pub variables: Variables, }
impl fmt::Debug for GMData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("GMData")
.field("meta", &self.meta)
.field("general_info", &self.general_info)
.finish_non_exhaustive()
}
}
impl GMData {
pub fn validate_names(&self) -> Result<()> {
let stopwatch = Stopwatch::start();
validate_names(&self.animation_curves, &self.strings)?;
validate_names(&self.audio_groups, &self.strings)?;
validate_names(&self.codes, &self.strings)?;
validate_names(&self.filter_effects, &self.strings)?;
validate_names(&self.fonts, &self.strings)?;
validate_names(&self.functions, &self.strings)?;
validate_names(&self.game_objects, &self.strings)?;
validate_names(&self.particle_systems, &self.strings)?;
validate_names(&self.paths, &self.strings)?;
validate_names(&self.rooms, &self.strings)?;
validate_names(&self.scripts, &self.strings)?;
validate_names(&self.sequences, &self.strings)?;
validate_names(&self.shaders, &self.strings)?;
validate_names(&self.sounds, &self.strings)?;
validate_names(&self.sprites, &self.strings)?;
validate_names(&self.texture_group_infos, &self.strings)?;
validate_names(&self.tilesets, &self.strings)?;
validate_names(&self.timelines, &self.strings)?;
self.variables.validate_names(&self.strings)?;
log::trace!("Validating all names took {stopwatch}");
Ok(())
}
pub fn deserialize_all_textures(&mut self) -> Result<()> {
let stopwatch = Stopwatch::start();
for texture_page in self.texture_pages.elements_mut() {
let Some(image) = &mut texture_page.image else {
continue;
};
let error: &str = "deserializing all embedded texture pages";
image.deserialize().ctx(error)?;
}
log::trace!(
"Deserializing all {} texture pages took {}",
self.texture_pages.len(),
stopwatch,
);
Ok(())
}
pub fn post_deserialize(&mut self) -> Result<()> {
self.validate_names()?;
self.deserialize_all_textures()?;
self.optimize_memory();
Ok(())
}
}