use bevy::{
asset::{AssetLoader, AssetPath, LoadContext, LoadedAsset},
prelude::*,
reflect::TypeUuid,
utils::{BoxedFuture, HashMap},
};
#[derive(TypeUuid)]
#[uuid = "abd7b6d9-633f-4322-a8f4-e5f011cae9c6"]
pub struct LdtkMap {
pub project: ldtk::Project,
pub tile_sets: HashMap<String, Handle<Texture>>,
}
pub(crate) fn add_assets(app: &mut AppBuilder) {
app.add_asset::<LdtkMap>()
.init_asset_loader::<LdtkMapLoader>();
}
#[derive(thiserror::Error, Debug)]
pub enum LdtkMapLoaderError {
#[error("Could not parese LDtk map file: {0}")]
ParsingError(#[from] serde_json::Error),
}
#[derive(Default)]
struct LdtkMapLoader;
impl AssetLoader for LdtkMapLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), anyhow::Error>> {
Box::pin(async move { Ok(load_ldtk(bytes, load_context).await?) })
}
fn extensions(&self) -> &[&str] {
&["ldtk", "ldtk.json"]
}
}
async fn load_ldtk<'a, 'b>(
bytes: &'a [u8],
load_context: &'a mut LoadContext<'b>,
) -> Result<(), LdtkMapLoaderError> {
let project: ldtk::Project = serde_json::from_slice(bytes)?;
let mut map = LdtkMap {
project,
tile_sets: Default::default(),
};
let mut dependencies = Vec::new();
for tileset in &map.project.defs.tilesets {
let file_path = load_context
.path()
.parent()
.unwrap()
.join(&tileset.rel_path);
let asset_path = AssetPath::new(file_path.clone(), None);
dependencies.push(asset_path.clone());
let handle: Handle<Texture> = load_context.get_handle(asset_path.clone());
map.tile_sets.insert(tileset.identifier.clone(), handle);
}
load_context.set_default_asset(LoadedAsset::new(map).with_dependencies(dependencies));
Ok(())
}