diff --git a/.gitpod.yml b/.gitpod.yml index 6360112..5ea8f7b 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -16,7 +16,7 @@ tasks: cargo test --all-features cargo test command: | - cargo watch -x 'test --tests' -x 'test --all-features' -x 'clippy --all-features --all-targets' -x '+nightly doc --all-features --no-deps' + cargo watch -x 'test --tests' -x 'test --features bevy-07' -x 'test --all-features' -x 'clippy --all-features --all-targets' -x '+nightly doc --all-features --no-deps' vscode: extensions: diff --git a/Cargo.toml b/Cargo.toml index 24fdd35..67d98e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ all-features = true [features] default = [] unstable-load-from-file = ["serde", "anyhow", "bevy_utils"] -bevy-07 = ["bevy-app-07", "bevy-sprite-07"] +bevy-07 = ["bevy-app-07", "bevy-asset-07", "bevy-sprite-07"] [dependencies] # Private dependencies (do not leak into the public API) @@ -31,10 +31,13 @@ anyhow = { version = "1.0", default-features = false, optional = true } bevy_core = { version = "0.7.0", default-features = false } bevy_ecs = { version = "0.7.0", default-features = false } bevy_reflect = { version = "0.7.0", default-features = false } -bevy_asset = { version = "0.7.0", default-features = false } + +bevy_utils = { version = "0.7.0", default-features = false, optional = true } + +# Bevy 0.7 bevy-app-07 = { package = "bevy_app",version = "0.7.0", default-features = false, optional = true } +bevy-asset-07 = { package = "bevy_asset", version = "0.7.0", default-features = false, optional = true } bevy-sprite-07 = { package = "bevy_sprite", version = "0.7.0", default-features = false, optional = true } -bevy_utils = { version = "0.7.0", default-features = false, optional = true } [dev-dependencies] bevy = { version = "0.7.0", default-features = false, features = ["render", "x11", "png"] } diff --git a/src/animation/load.rs b/src/animation/load.rs index 54d0b81..df5ac0b 100644 --- a/src/animation/load.rs +++ b/src/animation/load.rs @@ -1,9 +1,15 @@ -use super::SpriteSheetAnimation; -use bevy_asset::{AssetLoader, LoadContext, LoadedAsset}; -use bevy_utils::BoxedFuture; +use std::{error::Error, fmt::Display}; +use crate::SpriteSheetAnimation; + +use super::AnimationParseError; + +/// Loader of animation file +/// +/// It is not necessary to use this directly if you are using the bevy plugin, +/// as it is already registered as an asset loader. #[derive(Debug)] -pub(crate) struct SpriteSheetAnimationLoader { +pub struct SpriteSheetAnimationLoader { extensions: Vec<&'static str>, } @@ -25,28 +31,45 @@ impl Default for SpriteSheetAnimationLoader { } } -impl AssetLoader for SpriteSheetAnimationLoader { - fn load<'a>( - &'a self, - bytes: &'a [u8], - load_context: &'a mut LoadContext<'_>, - ) -> BoxedFuture<'a, Result<(), anyhow::Error>> { - Box::pin(async move { - let custom_asset = match load_context.path().extension().unwrap().to_str().unwrap() { - #[cfg(feature = "yaml")] - "yaml" | "yml" => SpriteSheetAnimation::from_yaml_bytes(bytes)?, - - #[cfg(feature = "ron")] - "ron" => SpriteSheetAnimation::from_ron_bytes(bytes)?, - - _ => unreachable!(), - }; - load_context.set_default_asset(LoadedAsset::new(custom_asset)); - Ok(()) - }) +impl SpriteSheetAnimationLoader { + /// Returns supported extensions + /// + /// [`SpriteSheetAnimationLoader::load`] can only succeed one of the returned extensions + #[must_use] + pub fn supported_extensions(&self) -> &[&str] { + &self.extensions } - fn extensions(&self) -> &[&str] { - &self.extensions + /// Load animation from file content + /// + /// # Errors + /// + /// Returns an error if the extension is not supported or if the data content is not valid for that extension + #[allow(clippy::unused_self)] + pub fn load( + &self, + extension: &str, + data: &[u8], + ) -> Result { + match extension { + #[cfg(feature = "yaml")] + "yaml" | "yml" => SpriteSheetAnimation::from_yaml_bytes(data), + + #[cfg(feature = "ron")] + "ron" => SpriteSheetAnimation::from_ron_bytes(data), + + _ => Err(AnimationParseError(UnexpectedExtension.into())), + } } } + +#[derive(Debug, Clone, Copy)] +struct UnexpectedExtension; + +impl Display for UnexpectedExtension { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Unexpected extension") + } +} + +impl Error for UnexpectedExtension {} diff --git a/src/animation.rs b/src/animation/mod.rs similarity index 98% rename from src/animation.rs rename to src/animation/mod.rs index 64079d7..eeb5c15 100644 --- a/src/animation.rs +++ b/src/animation/mod.rs @@ -8,6 +8,9 @@ use std::{ops::RangeInclusive, time::Duration}; use bevy_reflect::TypeUuid; +#[cfg(feature = "unstable-load-from-file")] +pub use load::SpriteSheetAnimationLoader; + #[cfg(feature = "unstable-load-from-file")] pub use parse::AnimationParseError; diff --git a/src/animation/parse.rs b/src/animation/parse.rs index 12a9cba..16c2f52 100644 --- a/src/animation/parse.rs +++ b/src/animation/parse.rs @@ -252,9 +252,10 @@ impl SpriteSheetAnimation { } } +/// Error when parsing an animation file content #[derive(Debug)] #[non_exhaustive] -pub struct AnimationParseError(anyhow::Error); +pub struct AnimationParseError(pub(crate) anyhow::Error); impl AnimationParseError { fn new(err: impl Error + Send + Sync + 'static) -> Self { diff --git a/src/integration/bevy_07.rs b/src/integration/bevy_07.rs index 97ace15..d2338e4 100644 --- a/src/integration/bevy_07.rs +++ b/src/integration/bevy_07.rs @@ -4,7 +4,9 @@ use crate::{ state::SpriteState, Play, PlaySpeedMultiplier, SpriteSheetAnimation, SpriteSheetAnimationState, }; use bevy_app_07::prelude::*; -use bevy_asset::prelude::*; +use bevy_asset_07::prelude::*; +#[cfg(feature = "unstable-load-from-file")] +use bevy_asset_07::{AssetLoader, BoxedFuture, LoadContext, LoadedAsset}; use bevy_core::prelude::*; use bevy_ecs::prelude::*; use bevy_sprite_07::prelude::*; @@ -115,3 +117,25 @@ impl<'w, T: SpriteState> SpriteState for Mut<'w, T> { self.deref_mut().set_current_index(index); } } + +#[cfg(feature = "unstable-load-from-file")] +impl AssetLoader for crate::animation::load::SpriteSheetAnimationLoader { + fn load<'a>( + &'a self, + bytes: &'a [u8], + load_context: &'a mut LoadContext<'_>, + ) -> BoxedFuture<'a, Result<(), anyhow::Error>> { + Box::pin(async move { + let custom_asset = self.load( + load_context.path().extension().unwrap().to_str().unwrap(), + bytes, + )?; + load_context.set_default_asset(LoadedAsset::new(custom_asset)); + Ok(()) + }) + } + + fn extensions(&self) -> &[&str] { + self.supported_extensions() + } +} diff --git a/src/lib.rs b/src/lib.rs index 0437647..c836c3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,6 +165,9 @@ pub use state::SpriteSheetAnimationState; #[allow(deprecated)] pub use animation::AnimationMode; +#[cfg(feature = "unstable-load-from-file")] +pub use animation::{AnimationParseError, SpriteSheetAnimationLoader}; + mod animation; pub mod integration; mod state;