use bevy_app::prelude::*;
use bevy_asset::{io::Reader, prelude::*, AssetLoader, LoadContext};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::prelude::*;
use bevy_reflect::prelude::*;
use derive_more::derive::{Display, Error, From};
use serde::{Deserialize, Serialize};
use crate::army::*;
use super::{graphics::sprite_sheet::*, paths::*};
pub struct ArmyAssetPlugin;
impl Plugin for ArmyAssetPlugin {
fn build(&self, app: &mut App) {
if !app.is_plugin_added::<AssetPathsPlugin>() {
app.add_plugins(AssetPathsPlugin);
}
if !app.is_plugin_added::<SpriteSheetAssetPlugin>() {
app.add_plugins(SpriteSheetAssetPlugin);
}
app.init_asset::<ArmyAsset>()
.init_asset_loader::<ArmyAssetLoader>();
#[cfg(feature = "bevy_reflect")]
app.register_asset_reflect::<ArmyAsset>();
}
}
#[derive(Asset, Clone, Default)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(not(feature = "bevy_reflect"), derive(TypePath))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Default))]
#[cfg_attr(all(feature = "bevy_reflect", feature = "debug"), reflect(Debug))]
pub struct ArmyAsset {
source: Army,
pub small_banners: Option<Handle<SpriteSheetAsset>>,
pub disabled_small_banners: Option<Handle<SpriteSheetAsset>>,
pub large_banners: Option<Handle<SpriteSheetAsset>>,
}
impl ArmyAsset {
#[inline(always)]
pub fn get(&self) -> &Army {
&self.source
}
}
#[derive(Clone, Component, Default, Deref, DerefMut, Eq, From, Hash, PartialEq, Reflect)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[reflect(Component, Default, Hash, PartialEq)]
#[cfg_attr(all(feature = "bevy_reflect", feature = "debug"), reflect(Debug))]
pub struct ArmyAssetHandle(pub Handle<ArmyAsset>);
impl From<ArmyAssetHandle> for AssetId<ArmyAsset> {
fn from(handle: ArmyAssetHandle) -> Self {
handle.id()
}
}
impl From<&ArmyAssetHandle> for AssetId<ArmyAsset> {
fn from(handle: &ArmyAssetHandle) -> Self {
handle.id()
}
}
#[derive(Clone, TypePath)]
pub struct ArmyAssetLoader {
paths: AssetPaths,
}
#[derive(Clone, Copy, Default, Deserialize, Reflect, Serialize)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[reflect(Default, Deserialize, Serialize)]
#[cfg_attr(all(feature = "bevy_reflect", feature = "debug"), reflect(Debug))]
pub struct ArmyAssetLoaderSettings {
pub load_small_banners: bool,
pub load_disabled_small_banners: bool,
pub load_large_banners: bool,
}
#[non_exhaustive]
#[derive(Debug, Display, Error, From)]
pub enum ArmyAssetLoaderError {
#[display("could not load asset: {_0}")]
Io(std::io::Error),
#[display("could not decode army: {_0}")]
DecodeError(DecodeError),
}
impl AssetLoader for ArmyAssetLoader {
type Asset = ArmyAsset;
type Settings = ArmyAssetLoaderSettings;
type Error = ArmyAssetLoaderError;
async fn load(
&self,
reader: &mut dyn Reader,
settings: &Self::Settings,
load_context: &mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let reader = std::io::Cursor::new(bytes);
let mut decoder = Decoder::new(reader);
let army = decoder.decode()?;
Ok(ArmyAsset {
source: army.clone(),
small_banners: if settings.load_small_banners {
Some(load_context.load(self.paths.resolve_path(&army.small_banners_path)))
} else {
None
},
disabled_small_banners: if settings.load_disabled_small_banners {
Some(load_context.load(self.paths.resolve_path(&army.disabled_small_banners_path)))
} else {
None
},
large_banners: if settings.load_large_banners {
Some(load_context.load(self.paths.resolve_path(&army.large_banners_path)))
} else {
None
},
})
}
fn extensions(&self) -> &[&str] {
&["ARM", "arm", "AUD", "aud", "ARE", "are"]
}
}
impl FromWorld for ArmyAssetLoader {
fn from_world(world: &mut World) -> Self {
let paths = world.resource::<AssetPaths>();
Self {
paths: paths.clone(),
}
}
}