Skip to content
Snippets Groups Projects
Verified Commit d8786405 authored by Louis's avatar Louis :fire:
Browse files

Import asset loader

parent e4e9e905
No related branches found
No related tags found
No related merge requests found
use std::marker::PhantomData;
use bevy::asset::LoadState;
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;
use bevy::reflect::{TypePath, TypeUuid};
use micro_banimate::definitions::AnimationSet;
use micro_ldtk::LdtkProject;
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 + TypePath + '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);
load_basic_type!(load_animation, AnimationSet => animations);
load_basic_type!(load_ldtk, LdtkProject => ldtk_projects);
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,
None,
None,
);
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]
}
}
mod loader;
mod resources;
mod startup;
mod _plugin {
use crate::assets::startup::{
check_load_resources, start_load_resources, start_preload_resources,
};
use crate::system::{run_in_setup, AppState};
use bevy::prelude::*;
pub struct AssetLoadingPlugin;
impl Plugin for AssetLoadingPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<super::resources::AssetHandles>()
.add_systems(
OnEnter(AppState::Preload),
(start_preload_resources, start_load_resources),
)
.add_systems(Update, check_load_resources.run_if(run_in_setup));
}
}
}
pub use _plugin::AssetLoadingPlugin;
pub(self) use loader::AssetTypeLoader;
pub use resources::AssetHandles;
pub(self) use resources::{AssetNameMapping, FixedAssetNameMapping, SpriteSheetConfig};
use bevy::prelude::*;
use bevy::utils::HashMap;
use micro_banimate::definitions::AnimationSet;
use micro_ldtk::LdtkProject;
use micro_musicbox::prelude::AudioSource;
use micro_musicbox::utilities::{SuppliesAudio, TrackType};
#[derive(Copy, Clone, Debug)]
pub struct SpriteSheetConfig {
pub tile_width: usize,
pub tile_height: usize,
pub columns: usize,
pub rows: usize,
}
impl SpriteSheetConfig {
pub fn squares(tile_wh: usize, columns: usize, rows: usize) -> Self {
Self {
tile_width: tile_wh,
tile_height: tile_wh,
columns,
rows,
}
}
pub fn rectangles(tile_width: usize, tile_height: usize, columns: usize, rows: usize) -> Self {
Self {
tile_width,
tile_height,
columns,
rows,
}
}
}
#[derive(Default, Resource)]
pub struct AssetHandles {
pub images: HashMap<String, Handle<Image>>,
pub atlas: HashMap<String, Handle<TextureAtlas>>,
pub sounds: HashMap<String, Handle<AudioSource>>,
pub fonts: HashMap<String, Handle<Font>>,
pub animations: HashMap<String, Handle<AnimationSet>>,
pub ldtk_projects: HashMap<String, Handle<LdtkProject>>,
}
macro_rules! fetch_wrapper {
($name: tt, $type: ty => $key: ident) => {
pub fn $name<T: ToString>(&self, name: T) -> Handle<$type> {
let key = name.to_string();
match self.$key.get(&key) {
Some(handle) => handle.clone_weak(),
None => {
let keys = self.$key.keys();
panic!(
"\n\nTried to fetch {} asset with a missing key: {}.\nPossible keys: {}\n\n",
stringify!($name),
name.to_string(),
keys.map(|k| format!("'{}'", k))
.collect::<Vec<String>>()
.join(", ")
)
}
}
}
};
}
impl AssetHandles {
fetch_wrapper!(image, Image => images);
fetch_wrapper!(atlas, TextureAtlas => atlas);
fetch_wrapper!(sound, AudioSource => sounds);
fetch_wrapper!(font, Font => fonts);
fetch_wrapper!(animation, AnimationSet => animations);
fetch_wrapper!(ldtk, LdtkProject => ldtk_projects);
}
impl SuppliesAudio for AssetHandles {
fn resolve_track_name<T: ToString>(&self, name: T) -> TrackType<String> {
if self.sounds.contains_key(&name.to_string()) {
TrackType::Single(name.to_string())
} else {
TrackType::Missing
}
}
fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>> {
self.sounds.get(&name.to_string()).map(Handle::clone_weak)
}
}
pub type AssetNameMapping = (String, String);
pub type FixedAssetNameMapping = (&'static str, &'static str);
use bevy::asset::LoadState;
use bevy::prelude::*;
use crate::assets::{AssetTypeLoader, SpriteSheetConfig};
use crate::system::AppState;
pub fn start_preload_resources(
mut _commands: Commands,
mut next_state: ResMut<NextState<AppState>>,
) {
// TODO: Add preload commands here
next_state.set(AppState::Setup);
}
pub fn start_load_resources(mut loader: AssetTypeLoader) {
loader.load_images(&[
("splash.png", "splash"),
("cresthollow.png", "menu_bg"),
("interface/basic_frame.png", "basic_frame"),
("interface/banner.png", "banner"),
("interface/button_pressed.png", "button_down"),
("interface/button_raised.png", "button_up"),
("interface/button_hover.png", "button_over"),
("interface/vertical_bar.png", "resource_bar"),
("interface/vertical_bar_bg.png", "resource_bar_bg"),
("interface/vertical_bar_fg.png", "resource_bar_fg"),
("interface/health_bar.png", "bar_red"),
("interface/mana_bar.png", "bar_blue"),
("interface/stamina_bar.png", "bar_yellow"),
("interface/energy_bar.png", "bar_green"),
]);
loader.load_audio(&[
("splash_sting.ogg", "splash_sting"),
("music/menu.ogg", "menu_track"),
("effects/running_001.ogg", "running_001"),
("effects/fire_crackle_001.ogg", "fire_crackle_001"),
("effects/cave_ambience.ogg", "cave_ambience"),
("effects/ui_confirm.ogg", "ui_confirm"),
("effects/ui_ping.ogg", "ui_ping"),
]);
loader.load_font(&[
("fonts/royal.ttf", "royal"),
("fonts/equipe.ttf", "equipe"),
("fonts/cursed.ttf", "cursed"),
("fonts/cursed_bold.ttf", "cursed_bold"),
]);
loader.load_spritesheet(
&SpriteSheetConfig::squares(16, 32, 64),
&[
("sheets/items.png", "items"),
("sheets/fx.png", "fx"),
("sheets/or_interface.png", "interface"),
("sheets/projectiles.png", "projectiles"),
],
);
loader.load_spritesheet(
&SpriteSheetConfig::squares(32, 16, 32),
&[
("sheets/creatures/town_guard_human.png", "town_guard_human"),
("sheets/creatures/town_guard_orc.png", "town_guard_orc"),
("sheets/creatures/town_guard_dwarf.png", "town_guard_dwarf"),
("sheets/creatures/town_guard_elf.png", "town_guard_elf"),
],
);
loader.load_spritesheet(
&SpriteSheetConfig::squares(32, 32, 32),
&[
("sheets/creatures/human_base.png", "human_base"),
("sheets/creatures/goblin_base.png", "goblin_base"),
("sheets/creatures/skeleton.png", "skeleton"),
("sheets/creatures/flame_acolyte.png", "flame_acolyte"),
("sheets/creatures/divine_warrior.png", "divine_warrior"),
],
);
loader.load_spritesheet(
&SpriteSheetConfig::squares(16, 64, 64),
&[
("sheets/world_dawn.png", "world"),
("sheets/characters.png", "characters"),
],
);
loader.load_animation(&[
("animations/humanoid.anim.json", "humanoid"),
("animations/skeleton.anim.json", "skeleton"),
("animations/flame_acolyte.anim.json", "flame_acolyte"),
("animations/guards.anim.json", "town_guards"),
]);
loader.load_ldtk(&[
("ldtk/dawnish.ldtk", "tile_data"),
("ldtk/cresthollow_world.ldtk", "cresthollow_world"),
]);
}
pub fn check_load_resources(
mut commands: Commands,
loader: AssetTypeLoader,
mut next_state: ResMut<NextState<AppState>>,
) {
let load_states = loader.get_all_load_state();
if load_states.iter().all(|state| *state == LoadState::Loaded) {
info!("Assets loaded successfully");
next_state.set(AppState::Splash);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment