use crate::asset_collection::AssetCollection;
use crate::dynamic_asset::{DynamicAssetCollection, DynamicAssetCollections};
use crate::loading_state::dynamic_asset_systems::{
check_dynamic_asset_collections, load_dynamic_asset_collections,
};
use crate::loading_state::systems::{
check_loading_collection, init_resource, start_loading_collection,
};
use crate::loading_state::{
InternalLoadingState, InternalLoadingStateSet, LoadingStateSchedule,
OnEnterInternalLoadingState,
};
use bevy::app::App;
use bevy::asset::Asset;
use bevy::ecs::schedule::SystemConfigs;
use bevy::prelude::{default, FromWorld, IntoSystemConfigs, Resource, States};
use bevy::utils::HashMap;
use std::any::TypeId;
pub trait ConfigureLoadingState {
#[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
fn load_collection<A: AssetCollection>(self) -> Self;
#[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
fn init_resource<R: Resource + FromWorld>(self) -> Self;
#[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
fn register_dynamic_asset_collection<C: DynamicAssetCollection + Asset>(self) -> Self;
#[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
fn with_dynamic_assets_file<C: DynamicAssetCollection + Asset>(self, file: &str) -> Self;
}
pub struct LoadingStateConfig<S: States> {
state: S,
on_enter_loading_assets: Vec<SystemConfigs>,
on_enter_loading_dynamic_asset_collections: Vec<SystemConfigs>,
on_update: Vec<SystemConfigs>,
on_enter_finalize: Vec<SystemConfigs>,
dynamic_assets: HashMap<TypeId, Vec<String>>,
}
impl<S: States> LoadingStateConfig<S> {
pub fn new(state: S) -> Self {
Self {
state,
on_enter_loading_assets: vec![],
on_enter_loading_dynamic_asset_collections: vec![],
on_update: vec![],
on_enter_finalize: vec![],
dynamic_assets: default(),
}
}
pub(crate) fn with_dynamic_assets_type_id(&mut self, file: &str, type_id: TypeId) {
let mut dynamic_files = self.dynamic_assets.remove(&type_id).unwrap_or_default();
dynamic_files.push(file.to_owned());
self.dynamic_assets.insert(type_id, dynamic_files);
}
pub(crate) fn build(mut self, app: &mut App) {
for config in self.on_enter_loading_assets {
app.add_systems(
OnEnterInternalLoadingState(
self.state.clone(),
InternalLoadingState::LoadingAssets,
),
config,
);
}
for config in self.on_update {
app.add_systems(LoadingStateSchedule(self.state.clone()), config);
}
for config in self.on_enter_finalize {
app.add_systems(
OnEnterInternalLoadingState(self.state.clone(), InternalLoadingState::Finalize),
config,
);
}
for config in self.on_enter_loading_dynamic_asset_collections {
app.add_systems(
OnEnterInternalLoadingState(
self.state.clone(),
InternalLoadingState::LoadingDynamicAssetCollections,
),
config,
);
}
let mut dynamic_assets = app
.world
.get_resource_mut::<DynamicAssetCollections<S>>()
.unwrap_or_else(|| {
panic!("Failed to get the DynamicAssetCollections resource for the loading state. Are you trying to configure a loading state before it was added to the bevy App?")
});
for (id, files) in self.dynamic_assets.drain() {
dynamic_assets.register_files_by_type_id(self.state.clone(), files, id);
}
}
}
impl<S: States> ConfigureLoadingState for LoadingStateConfig<S> {
fn load_collection<A: AssetCollection>(mut self) -> Self {
self.on_enter_loading_assets
.push(start_loading_collection::<S, A>.into_configs());
self.on_update.push(
check_loading_collection::<S, A>
.in_set(InternalLoadingStateSet::CheckAssets)
.into_configs(),
);
self
}
fn init_resource<R: Resource + FromWorld>(mut self) -> Self {
self.on_enter_finalize
.push(init_resource::<R>.into_configs());
self
}
fn register_dynamic_asset_collection<C: DynamicAssetCollection + Asset>(mut self) -> Self {
self.on_enter_loading_dynamic_asset_collections
.push(load_dynamic_asset_collections::<S, C>.into_configs());
self.on_update.push(
check_dynamic_asset_collections::<S, C>
.in_set(InternalLoadingStateSet::CheckDynamicAssetCollections),
);
self
}
fn with_dynamic_assets_file<C: DynamicAssetCollection + Asset>(mut self, file: &str) -> Self {
self.with_dynamic_assets_type_id(file, TypeId::of::<C>());
self
}
}