use bevy_app::prelude::*;
use bevy_asset::{io::Reader, prelude::*, AssetLoader, LoadContext};
use bevy_reflect::prelude::*;
use derive_more::derive::{Display, Error, From};
use glam::UVec2;
use serde::{Deserialize, Serialize};
use crate::gameflow::{DecodeError, Decoder};
pub struct GameflowAssetPlugin;
impl Plugin for GameflowAssetPlugin {
fn build(&self, app: &mut App) {
app.init_asset::<GameflowAsset>()
.init_asset_loader::<GameflowAssetLoader>();
#[cfg(feature = "bevy_reflect")]
app.register_asset_reflect::<GameflowAsset>();
}
}
#[derive(Clone, 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 GameflowPath {
pub control_points: Vec<UVec2>,
pub frames_per_point: u64,
pub curve_point_spacing: u32,
}
#[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 GameflowAsset {
pub paths: Vec<GameflowPath>,
pub animation_frame_interval_millis_x2: u64,
}
#[derive(Clone, Default, TypePath)]
pub struct GameflowAssetLoader;
#[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 GameflowAssetLoaderSettings;
#[non_exhaustive]
#[derive(Debug, Display, Error, From)]
pub enum GameflowAssetLoaderError {
#[display("could not load asset: {_0}")]
Io(std::io::Error),
#[display("could not decode gameflow: {_0}")]
DecodeError(DecodeError),
}
impl AssetLoader for GameflowAssetLoader {
type Asset = GameflowAsset;
type Settings = GameflowAssetLoaderSettings;
type Error = GameflowAssetLoaderError;
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 g = decoder.decode()?;
Ok(GameflowAsset {
paths: g
.paths
.into_iter()
.map(|p| GameflowPath {
control_points: p
.control_points
.into_iter()
.map(|p| UVec2::new(p.x, p.y))
.collect(),
frames_per_point: p.frames_per_point as u64,
curve_point_spacing: p.curve_point_spacing as u32,
})
.collect(),
animation_frame_interval_millis_x2: g.animation_frame_interval_millis_x2 as u64,
})
}
fn extensions(&self) -> &[&str] {
&["DOT", "dot"]
}
}