use std::collections::HashMap; use bevy::{asset::UntypedHandle, prelude::*}; use bevy_asset_loader::asset_collection::AssetCollection; use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; use strum_macros::EnumIter; use crate::{ AppState, fighter::{FighterAttributes, animation::AnimKind}, game_settings::GameSettings, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Reflect, EnumIter)] pub enum FighterId { TestFighter, } #[derive(Serialize, Deserialize, Clone, Asset, Reflect)] pub struct FighterManifest { pub id: FighterId, pub model_path: String, pub attributes: FighterAttributes, pub animations: HashMap, } #[derive(Resource)] pub struct FighterManifestAssets(pub Vec>); impl FighterManifestAssets { fn requested(world: &World) -> Self { let settings = world.resource::(); let asset_server = world.resource::(); Self( settings .fighter_manifest_paths .iter() .map(|path| asset_server.load(path.clone())) .collect(), ) } } impl AssetCollection for FighterManifestAssets { fn create(world: &mut World) -> Self { Self::requested(world) } fn load(world: &mut World) -> Vec { Self::requested(world) .0 .into_iter() .map(Handle::untyped) .collect() } } #[derive(Resource)] pub struct FighterManifestRegistry(HashMap>); impl FighterManifestRegistry { pub fn get(&self, fighter: FighterId) -> Option<&Handle> { self.0.get(&fighter) } } pub fn prepare_fighter_manifests( mut commands: Commands, handles: Res, manifests: Res>, mut next_state: ResMut>, ) { let mut registry = HashMap::with_capacity(handles.0.len()); for handle in &handles.0 { let Some(manifest) = manifests.get(handle) else { fail(&mut next_state, "a loaded fighter manifest is unavailable"); return; }; if manifest.model_path.is_empty() { fail( &mut next_state, &format!("{:?} has an empty model path", manifest.id), ); return; } if !manifest.animations.contains_key(&AnimKind::Wait) { fail( &mut next_state, &format!("{:?} has no Wait animation", manifest.id), ); return; } if registry.insert(manifest.id, handle.clone()).is_some() { fail( &mut next_state, &format!("duplicate manifest for {:?}", manifest.id), ); return; } } for fighter in FighterId::iter() { if !registry.contains_key(&fighter) { fail( &mut next_state, &format!("no manifest configured for {fighter:?}"), ); return; } } commands.insert_resource(FighterManifestRegistry(registry)); next_state.set(AppState::Idle); } fn fail(next_state: &mut NextState, message: &str) { error!("Fighter manifest preparation failed: {message}"); next_state.set(AppState::CommonAssetLoadFailed); }