Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify async loading in ldtk/tiled helpers #1

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 33 additions & 37 deletions examples/helpers/ldtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use bevy::{
use bevy::{
asset::{AssetLoader, AssetPath, LoadContext},
prelude::*,
utils::BoxedFuture,
};
use bevy_ecs_tilemap::map::TilemapType;

Expand Down Expand Up @@ -62,46 +61,43 @@ impl AssetLoader for LdtkLoader {
type Settings = ();
type Error = LdtkAssetLoaderError;

#[allow(refining_impl_trait)]
fn load<'a>(
async fn load<'a>(
&'a self,
reader: &'a mut Reader,
reader: &'a mut Reader<'_>,
_settings: &'a Self::Settings,
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<LdtkMap, Self::Error>> {
Box::pin(async move {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;

let project: ldtk_rust::Project = serde_json::from_slice(&bytes).map_err(|e| {
std::io::Error::new(
ErrorKind::Other,
format!("Could not read contents of Ldtk map: {e}"),
)
})?;
let dependencies: Vec<(i64, AssetPath)> = project
.defs
.tilesets
.iter()
.filter_map(|tileset| {
tileset.rel_path.as_ref().map(|rel_path| {
(
tileset.uid,
load_context.path().parent().unwrap().join(rel_path).into(),
)
})
load_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;

let project: ldtk_rust::Project = serde_json::from_slice(&bytes).map_err(|e| {
std::io::Error::new(
ErrorKind::Other,
format!("Could not read contents of Ldtk map: {e}"),
)
})?;
let dependencies: Vec<(i64, AssetPath)> = project
.defs
.tilesets
.iter()
.filter_map(|tileset| {
tileset.rel_path.as_ref().map(|rel_path| {
(
tileset.uid,
load_context.path().parent().unwrap().join(rel_path).into(),
)
})
.collect();
})
.collect();

let ldtk_map = LdtkMap {
project,
tilesets: dependencies
.iter()
.map(|dep| (dep.0, load_context.load(dep.1.clone())))
.collect(),
};
Ok(ldtk_map)
})
let ldtk_map = LdtkMap {
project,
tilesets: dependencies
.iter()
.map(|dep| (dep.0, load_context.load(dep.1.clone())))
.collect(),
};
Ok(ldtk_map)
}

fn extensions(&self) -> &[&str] {
Expand Down
149 changes: 73 additions & 76 deletions examples/helpers/tiled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use bevy::{
Res, Transform, Update,
},
reflect::TypePath,
utils::{BoxedFuture, HashMap},
utils::HashMap,
};
use bevy_ecs_tilemap::prelude::*;

Expand Down Expand Up @@ -105,90 +105,87 @@ impl AssetLoader for TiledLoader {
type Error = TiledAssetLoaderError;

#[allow(refining_impl_trait)]
ChristopherBiscardi marked this conversation as resolved.
Show resolved Hide resolved
fn load<'a>(
async fn load<'a>(
&'a self,
reader: &'a mut Reader,
reader: &'a mut Reader<'_>,
_settings: &'a Self::Settings,
load_context: &'a mut bevy::asset::LoadContext,
) -> BoxedFuture<'a, Result<Self::Asset, Self::Error>> {
Box::pin(async move {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;

let mut loader = tiled::Loader::with_cache_and_reader(
tiled::DefaultResourceCache::new(),
BytesResourceReader::new(&bytes),
);
let map = loader.load_tmx_map(load_context.path()).map_err(|e| {
std::io::Error::new(ErrorKind::Other, format!("Could not load TMX map: {e}"))
})?;

let mut tilemap_textures = HashMap::default();
#[cfg(not(feature = "atlas"))]
let mut tile_image_offsets = HashMap::default();

for (tileset_index, tileset) in map.tilesets().iter().enumerate() {
let tilemap_texture = match &tileset.image {
None => {
#[cfg(feature = "atlas")]
{
log::info!("Skipping image collection tileset '{}' which is incompatible with atlas feature", tileset.name);
continue;
}
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;

let mut loader = tiled::Loader::with_cache_and_reader(
tiled::DefaultResourceCache::new(),
BytesResourceReader::new(&bytes),
);
let map = loader.load_tmx_map(load_context.path()).map_err(|e| {
std::io::Error::new(ErrorKind::Other, format!("Could not load TMX map: {e}"))
})?;

let mut tilemap_textures = HashMap::default();
#[cfg(not(feature = "atlas"))]
let mut tile_image_offsets = HashMap::default();

for (tileset_index, tileset) in map.tilesets().iter().enumerate() {
let tilemap_texture = match &tileset.image {
None => {
#[cfg(feature = "atlas")]
{
log::info!("Skipping image collection tileset '{}' which is incompatible with atlas feature", tileset.name);
continue;
}

#[cfg(not(feature = "atlas"))]
{
let mut tile_images: Vec<Handle<Image>> = Vec::new();
for (tile_id, tile) in tileset.tiles() {
if let Some(img) = &tile.image {
// The load context path is the TMX file itself. If the file is at the root of the
// assets/ directory structure then the tmx_dir will be empty, which is fine.
let tmx_dir = load_context
.path()
.parent()
.expect("The asset load context was empty.");
let tile_path = tmx_dir.join(&img.source);
let asset_path = AssetPath::from(tile_path);
log::info!("Loading tile image from {asset_path:?} as image ({tileset_index}, {tile_id})");
let texture: Handle<Image> =
load_context.load(asset_path.clone());
tile_image_offsets
.insert((tileset_index, tile_id), tile_images.len() as u32);
tile_images.push(texture.clone());
}
#[cfg(not(feature = "atlas"))]
{
let mut tile_images: Vec<Handle<Image>> = Vec::new();
for (tile_id, tile) in tileset.tiles() {
if let Some(img) = &tile.image {
// The load context path is the TMX file itself. If the file is at the root of the
// assets/ directory structure then the tmx_dir will be empty, which is fine.
let tmx_dir = load_context
.path()
.parent()
.expect("The asset load context was empty.");
let tile_path = tmx_dir.join(&img.source);
let asset_path = AssetPath::from(tile_path);
log::info!("Loading tile image from {asset_path:?} as image ({tileset_index}, {tile_id})");
let texture: Handle<Image> = load_context.load(asset_path.clone());
tile_image_offsets
.insert((tileset_index, tile_id), tile_images.len() as u32);
tile_images.push(texture.clone());
}

TilemapTexture::Vector(tile_images)
}

TilemapTexture::Vector(tile_images)
}
Some(img) => {
// The load context path is the TMX file itself. If the file is at the root of the
// assets/ directory structure then the tmx_dir will be empty, which is fine.
let tmx_dir = load_context
.path()
.parent()
.expect("The asset load context was empty.");
let tile_path = tmx_dir.join(&img.source);
let asset_path = AssetPath::from(tile_path);
let texture: Handle<Image> = load_context.load(asset_path.clone());

TilemapTexture::Single(texture.clone())
}
};
}
Some(img) => {
// The load context path is the TMX file itself. If the file is at the root of the
// assets/ directory structure then the tmx_dir will be empty, which is fine.
let tmx_dir = load_context
.path()
.parent()
.expect("The asset load context was empty.");
let tile_path = tmx_dir.join(&img.source);
let asset_path = AssetPath::from(tile_path);
let texture: Handle<Image> = load_context.load(asset_path.clone());

TilemapTexture::Single(texture.clone())
}
};

tilemap_textures.insert(tileset_index, tilemap_texture);
}
tilemap_textures.insert(tileset_index, tilemap_texture);
}

let asset_map = TiledMap {
map,
tilemap_textures,
#[cfg(not(feature = "atlas"))]
tile_image_offsets,
};
let asset_map = TiledMap {
map,
tilemap_textures,
#[cfg(not(feature = "atlas"))]
tile_image_offsets,
};

log::info!("Loaded map: {}", load_context.path().display());
Ok(asset_map)
})
log::info!("Loaded map: {}", load_context.path().display());
Ok(asset_map)
}

fn extensions(&self) -> &[&str] {
Expand Down