Skip to content
Snippets Groups Projects
Verified Commit c75898be authored by Louis's avatar Louis :fire:
Browse files

Support external level files

parent a39c7a0a
No related branches found
No related tags found
No related merge requests found
......@@ -1567,7 +1567,7 @@ dependencies = [
[[package]]
name = "micro_ldtk"
version = "0.6.0"
version = "0.6.1"
dependencies = [
"anyhow",
"bevy",
......
......@@ -3,7 +3,7 @@ use std::collections::HashMap;
use bevy::prelude::*;
use crate::assets::{LevelIndex, TileMetadata, TilesetIndex};
use crate::ldtk::Project;
use crate::ldtk::{Level, Project};
use crate::{LdtkLevel, LevelDataUpdated};
pub fn handle_ldtk_project_events(
......@@ -18,9 +18,11 @@ pub fn handle_ldtk_project_events(
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
if let Some(project) = assets.get(handle) {
for level in project.get_all_levels() {
level_index
.insert(level.identifier.clone(), LdtkLevel::from(level.clone()));
update_events.send(LevelDataUpdated(level.identifier.clone()));
if level.external_rel_path.is_none() {
level_index
.insert(level.identifier.clone(), LdtkLevel::from(level.clone()));
update_events.send(LevelDataUpdated(level.identifier.clone()));
}
}
for tileset in &project.defs.tilesets {
......@@ -39,3 +41,22 @@ pub fn handle_ldtk_project_events(
}
}
}
pub fn handle_ldtk_level_events(
mut events: EventReader<AssetEvent<Level>>,
assets: Res<Assets<Level>>,
mut level_index: ResMut<LevelIndex>,
mut update_events: EventWriter<LevelDataUpdated>,
) {
for event in events.iter() {
match event {
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
if let Some(level) = assets.get(handle) {
level_index.insert(level.identifier.clone(), LdtkLevel::from(level.clone()));
update_events.send(LevelDataUpdated(level.identifier.clone()));
}
}
_ => {}
}
}
}
......@@ -15,7 +15,7 @@ mod data_1_2_5;
#[cfg(feature = "ldtk_1_3_0")]
mod data_1_3_0;
use bevy::asset::{AssetLoader, BoxedFuture, LoadContext, LoadedAsset};
use bevy::asset::{AssetLoader, AssetPath, BoxedFuture, LoadContext, LoadedAsset};
use bevy::reflect::{TypePath, TypeUuid, Uuid};
#[cfg(feature = "ldtk_1_0_0")]
pub use data_1_0_0::*;
......@@ -33,6 +33,7 @@ pub use data_1_2_4::*;
pub use data_1_2_5::*;
#[cfg(feature = "ldtk_1_3_0")]
pub use data_1_3_0::*;
use serde::Deserialize;
#[derive(thiserror::Error, Debug)]
pub enum ParseError {
......@@ -40,6 +41,42 @@ pub enum ParseError {
SerdeError(String),
}
pub trait LdtkFromBytes<'a>: Deserialize<'a> {
fn from_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
serde_json::from_slice(bytes).map_err(|e| ParseError::SerdeError(format!("{}", e)))
}
}
macro_rules! impl_from_bytes {
($type: tt) => {
impl<'a> From<&'a [u8]> for $type {
fn from(value: &'a [u8]) -> Self {
#[cfg(feature = "no_panic")]
{
match $type::from_bytes(value) {
Ok(val) => val,
Err(e) => {
log::error!("{}", e);
std::process::abort();
}
}
}
#[cfg(not(feature = "no_panic"))]
{
$type::from_bytes(value).expect("Failed to parse ldtk file")
}
}
}
};
}
impl<'a> LdtkFromBytes<'a> for Level {}
impl<'a> LdtkFromBytes<'a> for Project {}
impl_from_bytes!(Level);
impl_from_bytes!(Project);
impl TypeUuid for Project {
const TYPE_UUID: Uuid = Uuid::from_u128(87988914102923589138720617793417023455);
}
......@@ -53,11 +90,21 @@ impl TypePath for Project {
}
}
impl Project {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
serde_json::from_slice(bytes).map_err(|e| ParseError::SerdeError(format!("{}", e)))
impl TypeUuid for Level {
const TYPE_UUID: Uuid = Uuid::from_u128(18486863672600588966868281477384349187);
}
impl TypePath for Level {
fn type_path() -> &'static str {
"micro_ld0tk::ldtk::Level"
}
fn short_type_path() -> &'static str {
"Level"
}
}
impl Project {
pub fn get_all_levels(&self) -> Vec<&Level> {
if !self.worlds.is_empty() {
self.worlds
......@@ -99,26 +146,6 @@ impl Project {
pub type LdtkProject = Project;
impl<'a> From<&'a [u8]> for Project {
fn from(value: &'a [u8]) -> Self {
#[cfg(feature = "no_panic")]
{
match Project::from_bytes(value) {
Ok(val) => val,
Err(e) => {
log::error!("{}", e);
std::process::abort();
}
}
}
#[cfg(not(feature = "no_panic"))]
{
Project::from_bytes(value).expect("Failed to parse ldtk project file")
}
}
}
#[derive(Default)]
pub struct LdtkLoader;
impl AssetLoader for LdtkLoader {
......@@ -128,7 +155,27 @@ impl AssetLoader for LdtkLoader {
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, anyhow::Result<(), anyhow::Error>> {
Box::pin(async move {
load_context.set_default_asset(LoadedAsset::new(Project::from_bytes(bytes)?));
let project = Project::from_bytes(bytes)?;
let sub_levels = project
.levels
.iter()
.flat_map(|level| {
level
.external_rel_path
.as_ref()
.map(|rel_path| (level.identifier.clone(), rel_path.clone()))
})
.collect::<Vec<(String, String)>>();
let asset = LoadedAsset::new(project).with_dependencies(
sub_levels
.into_iter()
.map(|(id, path)| AssetPath::new(path.into(), Some(id)))
.collect(),
);
load_context.set_default_asset(asset);
Ok(())
})
}
......@@ -137,6 +184,24 @@ impl AssetLoader for LdtkLoader {
&["ldtk"]
}
}
#[derive(Default)]
pub struct LdtkLevelLoader;
impl AssetLoader for LdtkLevelLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, anyhow::Result<(), anyhow::Error>> {
Box::pin(async move {
load_context.set_default_asset(LoadedAsset::new(Level::from_bytes(bytes)?));
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["ldtkl"]
}
}
#[cfg(feature = "autotile")]
mod autotile_support {
......@@ -215,7 +280,7 @@ mod autotile_support {
#[cfg(test)]
mod test {
use crate::ldtk::Project;
use crate::ldtk::{LdtkFromBytes, Project};
#[cfg_attr(feature = "ldtk_1_2_5", test)]
pub fn load_project() {
......
......@@ -75,10 +75,13 @@ mod __plugin {
{
app.add_event::<super::system::LevelDataUpdated>()
.add_asset::<super::ldtk::Project>()
.add_asset::<super::ldtk::Level>()
.add_asset_loader(super::ldtk::LdtkLoader)
.add_asset_loader(super::ldtk::LdtkLevelLoader)
.init_resource::<super::assets::TilesetIndex>()
.init_resource::<super::assets::LevelIndex>()
.add_systems(Update, super::assets::handle_ldtk_project_events);
.add_systems(Update, super::assets::handle_ldtk_project_events)
.add_systems(Update, super::assets::handle_ldtk_level_events);
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment