pub mod asset;
pub mod loader;
pub(crate) mod spawn;
pub mod storage;
use crate::{
prelude::*,
tiled::{cache::TiledResourceCache, event::TiledMessageWriters},
};
use bevy::{asset::RecursiveDependencyLoadState, prelude::*};
#[derive(Component, Reflect, Clone, Debug, Deref)]
#[reflect(Component, Debug)]
#[require(
TiledMapStorage,
TiledMapLayerZOffset,
TiledMapImageRepeatMargin,
TilemapRenderSettings,
TilemapAnchor,
Visibility,
Transform
)]
pub struct TiledMap(pub Handle<TiledMapAsset>);
#[derive(Component, Reflect, Copy, Clone, Debug, Deref)]
#[reflect(Component, Default, Debug)]
pub struct TiledMapLayerZOffset(pub f32);
impl Default for TiledMapLayerZOffset {
fn default() -> Self {
Self(100.)
}
}
#[derive(Component, Reflect, Copy, Clone, Debug, Deref)]
#[reflect(Component, Default, Debug)]
pub struct TiledMapImageRepeatMargin(pub u32);
impl Default for TiledMapImageRepeatMargin {
fn default() -> Self {
Self(1)
}
}
#[derive(Component, Reflect, Copy, Clone, Debug, Deref)]
#[reflect(Component, Debug)]
pub struct TiledMapReference(pub Entity);
#[derive(Component, Default, Reflect, Copy, Clone, Debug)]
#[reflect(Component, Default, Debug)]
pub struct RespawnTiledMap;
pub(crate) fn plugin(app: &mut bevy::prelude::App) {
app.register_type::<TiledMap>();
app.register_type::<TiledMapLayerZOffset>();
app.register_type::<TiledMapImageRepeatMargin>();
app.register_type::<TiledMapReference>();
app.register_type::<RespawnTiledMap>();
app.add_systems(
PreUpdate,
process_loaded_maps.in_set(TiledPreUpdateSystems::ProcessLoadedMaps),
);
app.add_systems(
PostUpdate,
handle_map_events.in_set(TiledPostUpdateSystems::HandleMapAssetEvents),
);
app.add_plugins((asset::plugin, loader::plugin, storage::plugin));
}
fn process_loaded_maps(
asset_server: Res<AssetServer>,
mut commands: Commands,
maps: Res<Assets<TiledMapAsset>>,
mut map_query: Query<
(
Entity,
&TiledMap,
&mut TiledMapStorage,
&TilemapRenderSettings,
&TilemapAnchor,
&TiledMapLayerZOffset,
),
Or<(
Changed<TiledMap>,
Changed<TilemapAnchor>,
Changed<TiledMapLayerZOffset>,
Changed<TilemapRenderSettings>,
With<RespawnTiledMap>,
)>,
>,
mut message_writers: TiledMessageWriters,
) {
for (map_entity, map_handle, mut tiled_storage, render_settings, anchor, layer_offset) in
map_query.iter_mut()
{
if let Some(load_state) = asset_server.get_recursive_dependency_load_state(&map_handle.0) {
if !load_state.is_loaded() {
if let RecursiveDependencyLoadState::Failed(_) = load_state {
error!(
"Map failed to load, despawn it (handle = {:?})",
map_handle.0
);
commands.entity(map_entity).despawn();
} else {
debug!(
"Map is not fully loaded yet, will try again next frame (handle = {:?})",
map_handle.0
);
commands.entity(map_entity).insert(RespawnTiledMap);
}
continue;
}
let Some(tiled_map) = maps.get(&map_handle.0) else {
error!("Cannot get a valid TiledMapAsset out of Asset<TiledMapAsset>: has the last strong reference to the asset been dropped ? (handle = {:?})", map_handle.0);
commands.entity(map_entity).despawn();
continue;
};
debug!(
"Map has finished loading, spawn map layers (handle = {:?})",
map_handle.0
);
tiled_storage.clear(&mut commands);
spawn::spawn_map(
&mut commands,
map_entity,
map_handle.0.id(),
tiled_map,
&mut tiled_storage,
render_settings,
layer_offset,
&mut message_writers,
anchor,
);
commands.entity(map_entity).remove::<RespawnTiledMap>();
}
}
}
fn handle_map_events(
mut commands: Commands,
mut map_events: MessageReader<AssetEvent<TiledMapAsset>>,
map_query: Query<(Entity, &TiledMap)>,
mut cache: ResMut<TiledResourceCache>,
) {
for event in map_events.read() {
match event {
AssetEvent::Modified { id } => {
info!("Map changed: {id}");
cache.clear();
for (map_entity, map_handle) in map_query.iter() {
if map_handle.0.id() == *id {
commands.entity(map_entity).insert(RespawnTiledMap);
}
}
}
AssetEvent::Removed { id } => {
info!("Map removed: {id}");
for (map_entity, map_handle) in map_query.iter() {
if map_handle.0.id() == *id {
commands.entity(map_entity).despawn();
}
}
}
_ => continue,
}
}
}