use std::marker::PhantomData; use bevy::asset::LoadState; use bevy::ecs::system::SystemParam; use bevy::prelude::*; use bevy::reflect::TypeUuid; use micro_musicbox::prelude::AudioSource; use crate::assets::{AssetHandles, FixedAssetNameMapping, SpriteSheetConfig}; #[derive(SystemParam)] pub struct AssetTypeLoader<'w, 's> { pub handles: ResMut<'w, AssetHandles>, pub asset_server: Res<'w, AssetServer>, pub atlas: ResMut<'w, Assets<TextureAtlas>>, #[system_param(ignore)] marker: PhantomData<&'s usize>, } macro_rules! load_basic_type { ($name: tt, $type: ty => $key: ident) => { pub fn $name(&mut self, assets: &[FixedAssetNameMapping]) -> Vec<Handle<$type>> { self.load_list(assets, |loader, path, key| { let handle: Handle<$type> = loader.asset_server.load(&path); loader.handles.$key.insert(key, handle.clone()); handle }) } }; } macro_rules! load_state { ($container: expr => $key: ident) => { $container .asset_server .get_group_load_state($container.handles.$key.values().map(|f| f.id)) }; } impl<'w, 's> AssetTypeLoader<'w, 's> { fn load_list< T: Sync + Send + TypeUuid + 'static, Loader: Fn(&mut AssetTypeLoader, String, String) -> Handle<T>, >( &mut self, files: &[FixedAssetNameMapping], load: Loader, ) -> Vec<Handle<T>> { files .iter() .map(|(path, key)| load(self, path.to_string(), key.to_string())) .collect() } load_basic_type!(load_images, Image => images); load_basic_type!(load_audio, AudioSource => sounds); load_basic_type!(load_font, Font => fonts); pub fn load_spritesheet( &mut self, config: &SpriteSheetConfig, assets: &[FixedAssetNameMapping], ) -> Vec<Handle<Image>> { self.load_list(assets, |loader, path, key| { let handle: Handle<Image> = loader.asset_server.load(&path); loader .handles .images .insert(key.to_string(), handle.clone()); let atlas = TextureAtlas::from_grid( handle.clone(), Vec2::new(config.tile_width as f32, config.tile_height as f32), config.columns, config.rows, ); let atlas_handle = loader.atlas.add(atlas); loader.handles.atlas.insert(key, atlas_handle); handle }) } pub fn get_all_load_state(&self) -> Vec<LoadState> { let image_state = self .asset_server .get_group_load_state(self.handles.images.values().map(|f| f.id)); let atlas_state = self .asset_server .get_group_load_state(self.handles.images.values().map(|f| f.id)); vec![image_state, atlas_state] } }