use std::{
borrow::{Borrow, BorrowMut},
fmt::Debug,
marker::PhantomData,
mem::{replace, swap},
ops::{Deref, DerefMut},
};
use bevy_app::{App, Plugin};
use bevy_ecs::{prelude::*, query::QueryData, system::SystemParam};
use bevy_reflect::{FromReflect, Reflect, TypePath};
use bevy_utils::tracing::{debug, error, warn};
pub mod prelude {
pub use crate::{
transition, BehaviorPlugin, {Behavior, BehaviorBundle}, {BehaviorMut, BehaviorRef},
{Paused, Resumed, Started, Stopped},
{PausedEvent, ResumedEvent, StartedEvent, StoppedEvent},
};
}
#[cfg(test)]
mod tests;
pub struct BehaviorPlugin<B: Behavior>(PhantomData<B>);
impl<B: Behavior> Default for BehaviorPlugin<B> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<B: Behavior + FromReflect + TypePath> Plugin for BehaviorPlugin<B> {
fn build(&self, app: &mut App) {
app.add_event::<StartedEvent<B>>()
.add_event::<PausedEvent<B>>()
.add_event::<ResumedEvent<B>>()
.add_event::<StoppedEvent<B>>()
.register_type::<Memory<B>>()
.register_type::<Vec<B>>()
.register_type::<Transition<B>>();
}
}
pub trait Behavior: Component + Debug {
fn allows_next(&self, _next: &Self) -> bool {
true
}
fn is_resumable(&self) -> bool {
true
}
}
#[derive(Bundle, Default, Clone)]
pub struct BehaviorBundle<B: Behavior> {
behavior: B,
memory: Memory<B>,
transition: Transition<B>,
}
impl<B: Behavior> BehaviorBundle<B> {
pub fn new(behavior: B) -> Self {
assert!(
behavior.is_resumable(),
"initial behavior must be resumable"
);
Self {
behavior,
memory: Memory::default(),
transition: Transition::default(),
}
}
pub fn try_start(mut self, next: B) -> Self {
self.transition = Next(next);
self
}
}
impl<B: Behavior> From<B> for BehaviorBundle<B> {
fn from(behavior: B) -> Self {
Self::new(behavior)
}
}
#[derive(QueryData)]
pub struct BehaviorRef<B: Behavior> {
behavior: &'static B,
memory: &'static Memory<B>,
transition: &'static Transition<B>,
}
impl<B: Behavior> BehaviorRefItem<'_, B> {
pub fn get(&self) -> &B {
self.behavior
}
pub fn has_transition(&self) -> bool {
!matches!(self.transition, Transition::Empty)
}
pub fn previous(&self) -> Option<&B> {
self.memory.previous()
}
}
impl<B: Behavior> Deref for BehaviorRefItem<'_, B> {
type Target = B;
fn deref(&self) -> &Self::Target {
self.behavior
}
}
impl<B: Behavior> Borrow<B> for BehaviorRefItem<'_, B> {
fn borrow(&self) -> &B {
self.behavior
}
}
#[derive(QueryData)]
#[query_data(mutable)]
pub struct BehaviorMut<B: Behavior> {
behavior: &'static mut B,
memory: &'static Memory<B>,
transition: &'static mut Transition<B>,
}
impl<B: Behavior> BehaviorMutReadOnlyItem<'_, B> {
pub fn get(&self) -> &B {
self.behavior
}
pub fn has_transition(&self) -> bool {
!matches!(self.transition, Transition::Empty)
}
pub fn previous(&self) -> Option<&B> {
self.memory.previous()
}
}
impl<B: Behavior> Deref for BehaviorMutReadOnlyItem<'_, B> {
type Target = B;
fn deref(&self) -> &Self::Target {
self.behavior
}
}
impl<B: Behavior> Borrow<B> for BehaviorMutReadOnlyItem<'_, B> {
fn borrow(&self) -> &B {
self.behavior
}
}
impl<B: Behavior> BehaviorMutItem<'_, B> {
pub fn get(&self) -> &B {
&self.behavior
}
pub fn get_mut(&mut self) -> &mut B {
&mut self.behavior
}
pub fn has_transition(&self) -> bool {
!matches!(*self.transition, Transition::Empty)
}
pub fn try_start(&mut self, next: B) {
let previous = replace(self.transition.as_mut(), Next(next));
if !matches!(previous, Transition::Empty) {
warn!(
"transition override: {previous:?} -> {:?}",
self.transition.as_ref(),
);
}
}
pub fn stop(&mut self) {
let previous = replace(self.transition.as_mut(), Previous);
if !matches!(previous, Transition::Empty) {
warn!(
"transition override: {previous:?} -> {:?}",
self.transition.as_ref(),
);
}
}
pub fn reset(&mut self) {
let previous = replace(self.transition.as_mut(), Reset);
if !matches!(previous, Transition::Empty) {
warn!(
"transition override: {previous:?} -> {:?}",
self.transition.as_ref(),
);
}
}
pub fn previous(&self) -> Option<&B> {
self.memory.previous()
}
}
impl<B: Behavior> Deref for BehaviorMutItem<'_, B> {
type Target = B;
fn deref(&self) -> &Self::Target {
self.behavior.as_ref()
}
}
impl<B: Behavior> DerefMut for BehaviorMutItem<'_, B> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.behavior.as_mut()
}
}
impl<B: Behavior> Borrow<B> for BehaviorMutItem<'_, B> {
fn borrow(&self) -> &B {
self.behavior.as_ref()
}
}
impl<B: Behavior> BorrowMut<B> for BehaviorMutItem<'_, B> {
fn borrow_mut(&mut self) -> &mut B {
self.behavior.as_mut()
}
}
#[derive(Component, Clone, Reflect)]
#[reflect(Component)]
pub struct Memory<B: Behavior>(Vec<B>);
impl<B: Behavior> Memory<B> {
fn previous(&self) -> Option<&B> {
self.0.last()
}
fn len(&self) -> usize {
self.0.len()
}
fn push(&mut self, behavior: B) {
self.0.push(behavior)
}
fn pop(&mut self) -> Option<B> {
self.0.pop()
}
}
impl<B: Behavior> Default for Memory<B> {
fn default() -> Self {
Self(Vec::new())
}
}
#[derive(Component, Default, Clone, Debug, Reflect)]
#[reflect(Component)]
pub enum Transition<B: Behavior> {
#[default]
Empty,
#[reflect(ignore)]
Next(B),
#[reflect(ignore)]
Previous,
#[reflect(ignore)]
Reset,
}
pub use Transition::{Next, Previous, Reset};
impl<B: Behavior> Transition<B> {
fn take(&mut self) -> Self {
let mut t = Self::Empty;
swap(self, &mut t);
t
}
}
#[doc(hidden)]
#[derive(SystemParam)]
pub struct Events<'w, B: Behavior> {
started: EventWriter<'w, StartedEvent<B>>,
resumed: EventWriter<'w, ResumedEvent<B>>,
paused: EventWriter<'w, PausedEvent<B>>,
stopped: EventWriter<'w, StoppedEvent<B>>,
}
impl<'w, B: Behavior> Events<'w, B> {
fn send_started(&mut self, entity: Entity) {
self.started.send(StartedEvent::new(entity));
}
fn send_resumed(&mut self, entity: Entity) {
self.resumed.send(ResumedEvent::new(entity));
}
fn send_paused(&mut self, entity: Entity) {
self.paused.send(PausedEvent::new(entity));
}
fn send_stopped(&mut self, entity: Entity, behavior: B) {
self.stopped.send(StoppedEvent::new(entity, behavior));
}
}
#[derive(Event)]
pub struct StartedEvent<B: Behavior> {
entity: Entity,
marker: PhantomData<B>,
}
impl<B: Behavior> StartedEvent<B> {
fn new(entity: Entity) -> Self {
Self {
entity,
marker: PhantomData,
}
}
pub fn entity(&self) -> Entity {
self.entity
}
}
#[derive(Event)]
pub struct ResumedEvent<B: Behavior> {
entity: Entity,
marker: PhantomData<B>,
}
impl<B: Behavior> ResumedEvent<B> {
fn new(entity: Entity) -> Self {
Self {
entity,
marker: PhantomData,
}
}
pub fn entity(&self) -> Entity {
self.entity
}
}
#[derive(Event)]
pub struct PausedEvent<B: Behavior> {
entity: Entity,
marker: PhantomData<B>,
}
impl<B: Behavior> PausedEvent<B> {
fn new(entity: Entity) -> Self {
Self {
entity,
marker: PhantomData,
}
}
pub fn entity(&self) -> Entity {
self.entity
}
}
#[derive(Event)]
pub struct StoppedEvent<B: Behavior> {
entity: Entity,
behavior: B,
}
impl<B: Behavior> StoppedEvent<B> {
fn new(entity: Entity, behavior: B) -> Self {
Self { entity, behavior }
}
pub fn entity(&self) -> Entity {
self.entity
}
pub fn behavior(&self) -> &B {
&self.behavior
}
}
pub type Started<'w, 's, B> = EventReader<'w, 's, StartedEvent<B>>;
pub type Resumed<'w, 's, B> = EventReader<'w, 's, ResumedEvent<B>>;
pub type Paused<'w, 's, B> = EventReader<'w, 's, PausedEvent<B>>;
pub type Stopped<'w, 's, B> = EventReader<'w, 's, StoppedEvent<B>>;
#[allow(clippy::type_complexity)]
pub fn transition<B: Behavior>(
mut query: Query<(Entity, &mut B, &mut Memory<B>, &mut Transition<B>), Changed<Transition<B>>>,
mut events: Events<B>,
) {
for (entity, current, memory, mut transition) in &mut query {
match transition.bypass_change_detection().take() {
Next(next) => push(entity, next, current, memory, &mut events),
Previous => pop(entity, current, memory, &mut events),
Reset => reset(entity, current, memory, &mut events),
_ => (),
}
}
}
fn push<B: Behavior>(
entity: Entity,
mut next: B,
mut current: Mut<B>,
mut memory: Mut<Memory<B>>,
events: &mut Events<B>,
) {
if current.allows_next(&next) {
debug!("{entity:?}: {:?} -> {next:?}", *current);
let behavior = {
swap(current.as_mut(), &mut next);
next
};
if behavior.is_resumable() {
events.send_paused(entity);
memory.push(behavior);
} else {
events.send_stopped(entity, behavior);
}
events.send_started(entity);
} else {
warn!("{entity:?}: {:?} -> {next:?} is not allowed", *current);
}
}
fn pop<B: Behavior>(
entity: Entity,
mut current: Mut<B>,
mut memory: Mut<Memory<B>>,
events: &mut Events<B>,
) {
if let Some(mut next) = memory.pop() {
debug!("{entity:?}: {:?} -> {next:?}", *current);
let behavior = {
swap(current.as_mut(), &mut next);
next
};
events.send_resumed(entity);
events.send_stopped(entity, behavior);
} else {
error!("{entity:?}: {:?} -> None is not allowed", *current);
}
}
fn reset<B: Behavior>(
entity: Entity,
mut current: Mut<B>,
mut memory: Mut<Memory<B>>,
events: &mut Events<B>,
) {
while memory.len() > 1 {
let behavior = memory.pop().unwrap();
events.send_stopped(entity, behavior);
}
if let Some(mut next) = memory.pop() {
debug!("{entity:?}: {:?} -> {next:?}", *current);
let behavior = {
swap(current.as_mut(), &mut next);
next
};
events.send_resumed(entity);
events.send_stopped(entity, behavior);
} else {
warn!("{entity:?}: {:?} -> {:?} is redundant", *current, *current);
}
}