use bevy::asset::Handle;
use bevy::platform::collections::HashMap;
use bevy::prelude::{
Component,
Deref,
DerefMut,
Entity,
EntityEvent,
Image,
Message,
Reflect,
ReflectComponent,
Resource,
TextureAtlasLayout,
Timer,
};
use bevy::sprite::Sprite;
pub use bevy_2dviewangle_macro::View2dCollection;
use xxhash_rust::xxh3::xxh3_64;
pub trait View2dCollection {
fn get_all(
&self,
) -> Vec<(
Option<u64>,
Option<u64>,
Option<Angle>,
Option<&Handle<Image>>,
Option<&Handle<TextureAtlasLayout>>,
)>;
}
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Reflect, Default, Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum Angle {
Any,
#[default]
Front,
Back,
Left,
Right,
FrontLeft,
FrontRight,
BackLeft,
BackRight,
}
#[derive(Default, Clone)]
pub struct SpriteSheet {
pub layout: Option<Handle<TextureAtlasLayout>>,
pub image: Option<Handle<Image>>,
}
#[derive(Default, Deref, DerefMut)]
pub struct AngleSpriteSheets(HashMap<Angle, SpriteSheet>);
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Reflect, Clone)]
pub enum Notification {
LastFrame,
}
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
#[derive(Component, Reflect, Default, Clone)]
#[reflect(Component)]
#[require(Sprite)]
pub struct View2dActor {
pub angle: Angle,
pub action: u64,
pub next_action: Vec<u64>,
pub actor: u64,
pub flipped: bool,
pub animation_timer: Option<Timer>,
pub notify: Vec<Notification>,
}
#[derive(Resource, Deref, DerefMut, Default)]
pub struct ActorSpriteSheets(HashMap<u64, HashMap<u64, AngleSpriteSheets>>);
#[derive(Message)]
pub struct ViewChanged {
pub entity: Entity,
}
#[derive(EntityEvent)]
pub struct LastFrame {
pub entity: Entity,
}
#[derive(Message, EntityEvent)]
pub struct NextFrame {
pub entity: Entity,
}
impl AngleSpriteSheets {
pub fn from(items: Vec<(Angle, SpriteSheet)>) -> Self {
let mut map = HashMap::new();
for (key, value) in items {
map.insert(key, value);
}
Self(map)
}
}
impl ActorSpriteSheets {
pub fn load_asset_loader<T: View2dCollection>(&mut self, loader: &T) {
let mut actor_id = 0;
let mut action_id = 0;
for (actor, action, angle, image, atlas_layout) in loader.get_all() {
actor_id = actor.unwrap_or(actor_id);
action_id = action.unwrap_or(action_id);
let field_angle = angle.unwrap_or_default();
let actor;
if let Some(_actor) = self.get_mut(&actor_id) {
actor = _actor;
} else {
self.insert(actor_id, HashMap::default());
actor = self.get_mut(&actor_id).unwrap();
}
let action;
if let Some(_action) = actor.get_mut(&action_id) {
action = _action;
} else {
actor.insert(action_id, AngleSpriteSheets::default());
action = actor.get_mut(&action_id).unwrap();
}
let any = action.get(&Angle::Any).cloned();
let sprite;
if let Some(_sprite) = action.get_mut(&field_angle) {
sprite = _sprite;
} else {
action.insert(field_angle, SpriteSheet::default());
sprite = action.get_mut(&field_angle).unwrap();
}
if let Some(image_handle) = image {
sprite.image = Some(image_handle.clone());
} else if let Some(any) = any.as_ref() {
sprite.image.clone_from(&any.image);
}
if let Some(atlas_layout_handle) = atlas_layout {
sprite.layout = Some(atlas_layout_handle.clone());
} else if let Some(any) = any.as_ref() {
sprite.layout.clone_from(&any.layout);
}
if field_angle == Angle::Any {
let any = sprite.clone();
for s in action.values_mut() {
if s.image.is_none() {
s.image.clone_from(&any.image);
}
if s.layout.is_none() {
s.layout.clone_from(&any.layout);
}
}
}
}
}
}
pub fn get_act_id(act: &str) -> u64 {
xxh3_64(act.as_bytes())
}