use bevy::prelude::*;
pub trait EasyAssetLoader {
type AssetType: Asset;
fn asset_mapper() -> &'static [(&'static str, &'static str)];
}
#[derive(Resource)]
pub struct LoadAssets<S: States> {
pub target_state: S,
pub asset_count: u32,
pub current_loaded_assets: u32,
}
impl<S: States> LoadAssets<S> {
pub fn new(target_state: S) -> Self {
Self {
target_state,
asset_count: 0,
current_loaded_assets: 0,
}
}
}
pub fn load_assets_init<A: EasyAssetLoader + Struct + Resource>(
asset_server: Res<AssetServer>,
mut assets: ResMut<A>,
) {
for (asset, path) in A::asset_mapper() {
let handle: Handle<A::AssetType> = asset_server.load(*path);
if let Some(attribute) = assets.field_mut(asset) {
attribute.apply(&handle);
bevy::log::info!("Start loading field {} for asset loading", asset);
} else {
bevy::log::error!("Could initialize loading field {} for asset loading", asset);
}
}
}
pub fn load_assets_reset<S: States>(mut load_assets: ResMut<LoadAssets<S>>) {
load_assets.current_loaded_assets = 0;
load_assets.asset_count = 0;
bevy::log::info!("Reset loading status");
}
pub fn load_assets_check<A: EasyAssetLoader + Struct + Resource, S: States>(
asset_server: Res<AssetServer>,
assets: ResMut<A>,
mut load_assets: ResMut<LoadAssets<S>>,
) {
for (asset_attribute, _) in A::asset_mapper() {
bevy::log::info!("Check asset loading status for {}", asset_attribute);
if let Some(asset) = assets.field(asset_attribute) {
let any_asset = asset.as_any();
if let Some(handle) = any_asset.downcast_ref::<Handle<A::AssetType>>() {
if asset_server.is_loaded_with_dependencies(handle) {
load_assets.current_loaded_assets += 1;
bevy::log::info!("Asset {} is loaded", asset_attribute);
} else {
bevy::log::info!("Asset {} not loaded yet", asset_attribute);
}
load_assets.asset_count += 1;
} else {
bevy::log::error!(
"Could not downcast field {} for asset loading",
asset_attribute
);
}
} else {
bevy::log::error!("Could not load field {} for asset loading", asset_attribute);
}
}
}
pub fn load_assets_final_check<S: States + Clone>(
mut load_assets: ResMut<LoadAssets<S>>,
mut state: ResMut<NextState<S>>,
) {
if load_assets.current_loaded_assets == load_assets.asset_count {
state.set(load_assets.target_state.clone());
bevy::log::info!(
"All assets were loaded successfully ({})",
load_assets.asset_count
);
load_assets.current_loaded_assets = 0;
load_assets.asset_count = 0;
} else {
bevy::log::info!(
"Not all assets were loaded ({}/{})",
load_assets.current_loaded_assets,
load_assets.asset_count
);
}
}
pub struct LoadingPlugin<S: States + Clone>(pub S, pub S);
impl<S: States> Plugin for LoadingPlugin<S> {
fn build(&self, app: &mut App) {
app.insert_resource(LoadAssets::new(self.1.clone()))
.add_systems(
Update,
(load_assets_reset::<S>, load_assets_final_check::<S>)
.chain()
.run_if(in_state(self.0.clone())),
);
}
}
pub struct LoadPluginAssets<A: EasyAssetLoader + Struct + Resource + Clone, S: States + Clone>(
pub A,
pub S,
);
impl<A: EasyAssetLoader + Struct + Resource + Clone, S: States + Clone> Plugin
for LoadPluginAssets<A, S>
{
fn build(&self, app: &mut App) {
app.insert_resource(self.0.clone())
.add_systems(OnEnter(self.1.clone()), load_assets_init::<A>)
.add_systems(
Update,
load_assets_check::<A, S>
.run_if(in_state(self.1.clone()))
.after(load_assets_reset::<S>)
.before(load_assets_final_check::<S>),
);
}
}