use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use anyhow::Error; use bevy::asset::{AssetEvent, AssetLoader, Assets, BoxedFuture, LoadContext, LoadedAsset}; use bevy::prelude::{EventReader, EventWriter, Res, ResMut, Resource}; use bevy::reflect::TypeUuid; use ldtk_rust::Project; use serde_json::Value; use crate::utils::SerdeClone; use crate::{LdtkLevel, LevelDataUpdated}; #[derive(TypeUuid)] #[uuid = "292a8918-9487-11ed-8dd2-43b6f36cb076"] pub struct LdtkProject(pub Project); impl Deref for LdtkProject { type Target = Project; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for LdtkProject { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl LdtkProject {} #[derive(Default)] pub struct LdtkLoader; impl AssetLoader for LdtkLoader { fn load<'a>( &'a self, bytes: &'a [u8], load_context: &'a mut LoadContext, ) -> BoxedFuture<'a, anyhow::Result<(), Error>> { Box::pin(async move { let mut ldtk: Project = serde_json::from_slice(bytes)?; if ldtk.external_levels { ldtk.load_external_levels(load_context.path()); } load_context.set_default_asset(LoadedAsset::new(LdtkProject(ldtk))); Ok(()) }) } fn extensions(&self) -> &[&str] { &["ldtk"] } } #[derive(Resource, Default)] pub struct LevelIndex(pub HashMap<String, LdtkLevel>); impl Deref for LevelIndex { type Target = HashMap<String, LdtkLevel>; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for LevelIndex { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } #[derive(Default)] pub struct TileMetadata(pub HashMap<i64, Value>); #[derive(Resource, Default)] pub struct TilesetIndex(pub HashMap<String, TileMetadata>); impl Deref for TilesetIndex { type Target = HashMap<String, TileMetadata>; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for TilesetIndex { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } pub fn handle_ldtk_project_events( mut events: EventReader<AssetEvent<LdtkProject>>, assets: Res<Assets<LdtkProject>>, mut level_index: ResMut<LevelIndex>, mut tilset_index: ResMut<TilesetIndex>, mut update_events: EventWriter<LevelDataUpdated>, ) { for event in events.iter() { match event { AssetEvent::Created { handle } | AssetEvent::Modified { handle } => { if let Some(LdtkProject(project)) = assets.get(handle) { for level in &project.levels { level_index.insert( level.identifier.clone(), LdtkLevel::from(level.serde_clone()), ); update_events.send(LevelDataUpdated(level.identifier.clone())); } for tileset in &project.defs.tilesets { let mut tile_meta = HashMap::new(); for custom in &tileset.custom_data { tile_meta.insert( custom.tile_id, serde_json::from_str(&custom.data).unwrap(), ); } tilset_index.insert(tileset.identifier.clone(), TileMetadata(tile_meta)); } } } _ => {} } } }