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, Res, ResMut, Resource}; use bevy::reflect::TypeUuid; use ldtk_rust::{Level, Project, TilesetDefinition}; use serde_json::Value; use crate::utils::SerdeClone; #[derive(TypeUuid)] #[uuid = "eb97c508-61ea-11ed-abd3-db91dd0a6e8b"] 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, Level>); impl Deref for LevelIndex { type Target = HashMap<String, Level>; 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>, ) { 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(), level.serde_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)); } } } _ => {} } } }