use bevy::utils::HashMap;
use std::any::TypeId;
use std::fmt::Debug;
use bevy::asset::{Asset, AssetServer, UntypedHandle};
use bevy::ecs::schedule::States;
use bevy::ecs::system::Resource;
use bevy::ecs::world::World;
use std::marker::PhantomData;
#[derive(Debug)]
pub enum DynamicAssetType {
Single(UntypedHandle),
Collection(Vec<UntypedHandle>),
}
pub trait DynamicAsset: Debug + Send + Sync {
fn load(&self, asset_server: &AssetServer) -> Vec<UntypedHandle>;
fn build(&self, world: &mut World) -> Result<DynamicAssetType, anyhow::Error>;
}
#[derive(Resource, Default)]
pub struct DynamicAssets {
key_asset_map: HashMap<String, Box<dyn DynamicAsset>>,
}
impl DynamicAssets {
pub fn get_asset(&self, key: &str) -> Option<&dyn DynamicAsset> {
self.key_asset_map.get(key).map(|boxed| boxed.as_ref())
}
pub fn iter_assets(&self) -> impl Iterator<Item = (&str, &dyn DynamicAsset)> {
self.key_asset_map
.iter()
.map(|(k, v)| (k.as_str(), v.as_ref()))
}
pub fn register_asset<K: Into<String>>(&mut self, key: K, asset: Box<dyn DynamicAsset>) {
self.key_asset_map.insert(key.into(), asset);
}
}
pub trait DynamicAssetCollection {
fn register(&self, dynamic_assets: &mut DynamicAssets);
}
#[derive(Resource, Debug)]
pub struct DynamicAssetCollections<State: States> {
files: HashMap<State, HashMap<TypeId, Vec<String>>>,
_marker: PhantomData<State>,
}
impl<State: States> DynamicAssetCollections<State> {
pub fn register_file<C: DynamicAssetCollection + Asset>(
&mut self,
loading_state: State,
file: &str,
) {
self.register_file_by_type_id(loading_state, file, TypeId::of::<C>());
}
pub(crate) fn register_files_by_type_id(
&mut self,
loading_state: State,
mut files: Vec<String>,
type_id: TypeId,
) {
let mut dynamic_collections_for_state =
self.files.remove(&loading_state).unwrap_or_default();
let mut dynamic_files = dynamic_collections_for_state
.remove(&type_id)
.unwrap_or_default();
dynamic_files.append(&mut files);
dynamic_collections_for_state.insert(type_id, dynamic_files);
self.files
.insert(loading_state, dynamic_collections_for_state);
}
pub(crate) fn register_file_by_type_id(
&mut self,
loading_state: State,
file: &str,
type_id: TypeId,
) {
let mut dynamic_collections_for_state =
self.files.remove(&loading_state).unwrap_or_default();
let mut dynamic_files = dynamic_collections_for_state
.remove(&type_id)
.unwrap_or_default();
dynamic_files.push(file.to_owned());
dynamic_collections_for_state.insert(type_id, dynamic_files);
self.files
.insert(loading_state, dynamic_collections_for_state);
}
pub fn get_files<C: DynamicAssetCollection + Asset>(
&self,
loading_state: &State,
) -> Option<&Vec<String>> {
let files = self.files.get(loading_state)?;
files.get(&TypeId::of::<C>())
}
}
impl<State: States> Default for DynamicAssetCollections<State> {
fn default() -> Self {
DynamicAssetCollections {
files: HashMap::default(),
_marker: PhantomData,
}
}
}