use bevy_app::prelude::*;
use bevy_asset::{io::Reader, prelude::*, AssetLoader, LoadContext};
use bevy_reflect::prelude::*;
use derive_more::derive::{Display, Error, From};
use serde::{Deserialize, Serialize};
use crate::battle_tabletop::*;
use super::army::*;
pub struct BattleTabletopAssetPlugin;
impl Plugin for BattleTabletopAssetPlugin {
fn build(&self, app: &mut App) {
if !app.is_plugin_added::<ArmyAssetPlugin>() {
app.add_plugins(ArmyAssetPlugin);
}
app.init_asset::<BattleTabletopAsset>()
.init_asset_loader::<BattleTabletopAssetLoader>();
#[cfg(feature = "bevy_reflect")]
app.register_asset_reflect::<BattleTabletopAsset>();
}
}
#[derive(Asset, Clone)]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(not(feature = "bevy_reflect"), derive(TypePath))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
#[cfg_attr(all(feature = "bevy_reflect", feature = "debug"), reflect(Debug))]
pub struct BattleTabletopAsset {
source: BattleTabletop,
pub army1: Option<Handle<ArmyAsset>>,
pub army2: Option<Handle<ArmyAsset>>,
}
impl BattleTabletopAsset {
#[inline(always)]
pub fn get(&self) -> &BattleTabletop {
&self.source
}
#[inline(always)]
pub fn objectives(&self) -> &[Objective] {
&self.source.objectives
}
#[inline(always)]
pub fn obstacles(&self) -> &[Obstacle] {
&self.source.obstacles
}
#[inline(always)]
pub fn regions(&self) -> &[Region] {
&self.source.regions
}
#[inline(always)]
pub fn nodes(&self) -> &[Node] {
&self.source.nodes
}
}
#[derive(Clone, Default, TypePath)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct BattleTabletopAssetLoader;
#[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 BattleTabletopAssetLoaderSettings {
pub load_army1: bool,
pub army1_loader_settings: Option<ArmyAssetLoaderSettings>,
pub load_army2: bool,
pub army2_loader_settings: Option<ArmyAssetLoaderSettings>,
}
#[non_exhaustive]
#[derive(Debug, Display, Error, From)]
pub enum BattleTabletopAssetLoaderError {
#[display("could not load asset: {_0}")]
Io(std::io::Error),
#[display("could not decode battle tabletop: {_0}")]
DecodeError(DecodeError),
}
impl AssetLoader for BattleTabletopAssetLoader {
type Asset = BattleTabletopAsset;
type Settings = BattleTabletopAssetLoaderSettings;
type Error = BattleTabletopAssetLoaderError;
async fn load(
&self,
reader: &mut dyn Reader,
settings: &Self::Settings,
load_context: &mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let parent_path = load_context
.path()
.path()
.parent()
.expect("parent path should exist")
.to_path_buf();
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 btb = decoder.decode()?;
Ok(BattleTabletopAsset {
source: btb.clone(),
army1: if settings.load_army1 {
let mut b = load_context.loader();
if let Some(ref s) = settings.army1_loader_settings {
let s = *s;
b = b.with_settings(move |settings| {
*settings = s;
});
}
Some(b.load(parent_path.join(btb.army1_file_stem).with_extension("ARM")))
} else {
None
},
army2: if settings.load_army2 {
let mut b = load_context.loader();
if let Some(ref s) = settings.army2_loader_settings {
let s = *s;
b = b.with_settings(move |settings| {
*settings = s;
});
}
Some(b.load(parent_path.join(btb.army2_file_stem).with_extension("ARM")))
} else {
None
},
})
}
fn extensions(&self) -> &[&str] {
&["BTB", "btb"]
}
}