Skip to content
Snippets Groups Projects
assets.rs 2.9 KiB
Newer Older
Louis's avatar
Louis committed
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};

use anyhow::Error;
use bevy::asset::{AssetEvent, AssetLoader, Assets, BoxedFuture, LoadContext, LoadedAsset};
Louis's avatar
Louis committed
use bevy::prelude::{EventReader, EventWriter, Res, ResMut, Resource};
Louis's avatar
Louis committed
use bevy::reflect::TypeUuid;
use ldtk_rust::Project;
Louis's avatar
Louis committed
use serde_json::Value;

use crate::utils::SerdeClone;
Louis's avatar
Louis committed
use crate::{LdtkLevel, LevelDataUpdated};
Louis's avatar
Louis committed

#[derive(TypeUuid)]
Louis's avatar
Louis committed
#[uuid = "292a8918-9487-11ed-8dd2-43b6f36cb076"]
Louis's avatar
Louis committed
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>);
Louis's avatar
Louis committed
impl Deref for LevelIndex {
	type Target = HashMap<String, LdtkLevel>;
Louis's avatar
Louis committed
	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>,
Louis's avatar
Louis committed
	mut update_events: EventWriter<LevelDataUpdated>,
Louis's avatar
Louis committed
) {
	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()),
						);
Louis's avatar
Louis committed
						update_events.send(LevelDataUpdated(level.identifier.clone()));
Louis's avatar
Louis committed
					}

					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(),
Louis's avatar
Louis committed
							);
						}
						tilset_index.insert(tileset.identifier.clone(), TileMetadata(tile_meta));
					}
				}
			}
			_ => {}
		}
	}
}