use std::fmt;
use std::path::PathBuf;
use crate::prelude::*;
use crate::util::bench::Stopwatch;
use crate::wad::elements::animation_curve::GMAnimationCurves;
use crate::wad::elements::audio::GMAudios;
use crate::wad::elements::audio_group::GMAudioGroups;
use crate::wad::elements::background::GMBackgrounds;
use crate::wad::elements::code::GMCodes;
use crate::wad::elements::embedded_image::GMEmbeddedImages;
use crate::wad::elements::extension::GMExtensions;
use crate::wad::elements::feature_flag::GMFeatureFlags;
use crate::wad::elements::filter_effect::GMFilterEffects;
use crate::wad::elements::font::GMFonts;
use crate::wad::elements::function::GMFunctions;
use crate::wad::elements::game_end::GMGameEndScripts;
use crate::wad::elements::game_object::GMGameObjects;
use crate::wad::elements::general_info::GMGeneralInfo;
use crate::wad::elements::global_init::GMGlobalInitScripts;
use crate::wad::elements::language::GMLanguageInfo;
use crate::wad::elements::options::GMOptions;
use crate::wad::elements::particle_emitter::GMParticleEmitters;
use crate::wad::elements::particle_system::GMParticleSystems;
use crate::wad::elements::path::GMPaths;
use crate::wad::elements::room::GMRooms;
use crate::wad::elements::script::GMScripts;
use crate::wad::elements::sequence::GMSequences;
use crate::wad::elements::shader::GMShaders;
use crate::wad::elements::sound::GMSounds;
use crate::wad::elements::sprite::GMSprites;
use crate::wad::elements::tag::GMTags;
use crate::wad::elements::texture_group_info::GMTextureGroupInfos;
use crate::wad::elements::texture_page::GMTexturePages;
use crate::wad::elements::texture_page_item::GMTexturePageItems;
use crate::wad::elements::timeline::GMTimelines;
use crate::wad::elements::ui_node::GMRootUINodes;
use crate::wad::elements::validate_names;
use crate::wad::elements::variable::GMVariables;
#[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,
}
impl Default for Metadata {
fn default() -> Self {
Self {
location: None,
chunk_padding: 16,
endianness: Endianness::Little,
original_data_size: 0,
}
}
}
#[derive(Clone, Default)]
pub struct GMData {
pub meta: Metadata,
pub animation_curves: GMAnimationCurves, pub audio_groups: GMAudioGroups, pub audios: GMAudios, pub backgrounds: GMBackgrounds, pub codes: GMCodes, pub embedded_images: GMEmbeddedImages, pub extensions: GMExtensions, pub feature_flags: GMFeatureFlags, pub filter_effects: GMFilterEffects, pub fonts: GMFonts, pub functions: GMFunctions, pub game_end_scripts: GMGameEndScripts, pub game_objects: GMGameObjects, pub general_info: GMGeneralInfo, pub global_init_scripts: GMGlobalInitScripts, pub language_info: GMLanguageInfo, pub options: GMOptions, pub particle_emitters: GMParticleEmitters, pub particle_systems: GMParticleSystems, pub paths: GMPaths, pub rooms: GMRooms, pub ui_nodes: GMRootUINodes, pub scripts: GMScripts, pub sequences: GMSequences, pub shaders: GMShaders, pub sounds: GMSounds, pub sprites: GMSprites, pub tags: GMTags, pub texture_group_infos: GMTextureGroupInfos, pub texture_page_items: GMTexturePageItems, pub texture_pages: GMTexturePages, pub timelines: GMTimelines, pub variables: GMVariables, }
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)?;
validate_names(&self.audio_groups)?;
validate_names(&self.backgrounds)?;
validate_names(&self.codes)?;
validate_names(&self.embedded_images)?;
validate_names(&self.filter_effects)?;
validate_names(&self.fonts)?;
validate_names(&self.functions)?;
validate_names(&self.game_objects)?;
validate_names(&self.particle_emitters)?;
validate_names(&self.particle_systems)?;
validate_names(&self.paths)?;
validate_names(&self.rooms)?;
validate_names(&self.scripts)?;
validate_names(&self.sequences)?;
validate_names(&self.shaders)?;
validate_names(&self.sounds)?;
validate_names(&self.sprites)?;
validate_names(&self.texture_group_infos)?;
log::trace!("Validating all names took {stopwatch}");
Ok(())
}
pub fn deserialize_all_textures(&mut self) -> Result<()> {
let stopwatch = Stopwatch::start();
for texture_page in &mut self.texture_pages {
let Some(image) = &mut texture_page.image else {
continue;
};
let error: &str = "deserializing all embedded texture pages";
image.deserialize().context(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(())
}
}