Skip to main content

moonshine_behavior/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![allow(clippy::match_single_binding)] // For default trait method impls
4#![allow(clippy::match_like_matches_macro)]
5
6/// Common elements for [`Behavior`] query and management.
7pub mod prelude {
8    pub use crate::{Behavior, BehaviorIndex, BehaviorItem, BehaviorMut, BehaviorRef};
9    pub use moonshine_kind::{Instance, InstanceCommands};
10
11    pub use crate::transition::{
12        transition, Interrupt, Interruption, Next, Previous, Transition, TransitionQueue,
13    };
14
15    pub use crate::events::{OnActivate, OnPause, OnResume, OnStart, OnStop};
16    pub use crate::plugin::BehaviorPlugin;
17
18    pub use crate::match_next;
19
20    #[allow(deprecated)]
21    pub use crate::transition::TransitionSequence;
22}
23
24pub mod events;
25pub mod transition;
26
27mod plugin;
28
29#[cfg(test)]
30mod tests;
31
32use std::fmt::Debug;
33use std::mem::{replace, swap};
34use std::ops::{Deref, DerefMut, Index, IndexMut};
35
36use bevy_derive::{Deref, DerefMut};
37use bevy_ecs::change_detection::{MaybeLocation, Tick};
38use bevy_ecs::component::Mutable;
39use bevy_ecs::event::EntityTrigger;
40use bevy_ecs::{prelude::*, query::QueryData};
41use bevy_log::prelude::*;
42use bevy_reflect::prelude::*;
43use moonshine_kind::prelude::*;
44
45pub use plugin::BehaviorPlugin;
46
47use crate::events::{Activate, Error, Pause, Resume, Start, Stop};
48
49use self::transition::*;
50
51/// Any [`Component`] which may be used as a [`Behavior`].
52///
53/// # Usage
54///
55/// A [`Behavior`] is a component which represents a set of finite states. This makes `enum` the ideal data structure
56/// to implement this trait, however this is not a strict requirement.
57pub trait Behavior: Component<Mutability = Mutable> + Debug + Sized {
58    /// Called when an interrupt is requested.
59    ///
60    /// If this returns `true`, the current behavior will stop to allow the next behavior to start.
61    /// The initial behavior is never allowed to yield.
62    fn filter_yield(&self, next: &Self) -> bool {
63        match_next! {
64            self => next,
65            _ => _,
66        }
67    }
68
69    /// Called before a new behavior is started.
70    ///
71    /// If this returns `false`, the transition fails.
72    /// See [`Error`] for details on how to handle transition failures.
73    fn filter_next(&self, next: &Self) -> bool {
74        match_next! {
75            self => next,
76            _ => _,
77        }
78    }
79
80    /// Called after a behavior is paused.
81    ///
82    /// If this returns `false`, the paused behavior will be stopped immediatedly and discarded.
83    /// No [`Pause`] event will be sent in this case.
84    fn is_resumable(&self) -> bool {
85        match self {
86            _ => true,
87        }
88    }
89
90    /// Called during [`transition`](transition::transition) just after the behavior is started.
91    fn on_start(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
92
93    /// Called during [`transition`](transition::transition) just after the behavior is paused.
94    fn on_pause(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
95
96    /// Called during [`transition`](transition::transition) just after the behavior is resumed.
97    fn on_resume(&self, _previous: &Self, _commands: InstanceCommands<Self>) {}
98
99    /// Called during [`transition`](transition::transition) just after the behavior is stopped.
100    fn on_stop(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
101
102    /// Called during [`transition`](transition::transition) just after the behavior is started *or* resumed.
103    fn on_activate(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
104
105    /// Called during [`transition`](transition::transition) just after the behavior is paused *or* stopped.
106    fn on_suspend(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
107}
108
109#[doc(hidden)]
110trait BehaviorHooks: Behavior {
111    fn invoke_start(&self, previous: Option<&Self>, mut commands: InstanceCommands<Self>) {
112        self.on_start(previous, commands.reborrow());
113        self.on_activate(previous, commands);
114    }
115
116    fn invoke_pause(&self, current: &Self, mut commands: InstanceCommands<Self>) {
117        self.on_suspend(current, commands.reborrow());
118        self.on_pause(current, commands);
119    }
120
121    fn invoke_resume(&self, previous: &Self, mut commands: InstanceCommands<Self>) {
122        self.on_resume(previous, commands.reborrow());
123        self.on_activate(Some(previous), commands);
124    }
125
126    fn invoke_stop(&self, current: &Self, mut commands: InstanceCommands<Self>) {
127        self.on_suspend(current, commands.reborrow());
128        self.on_stop(current, commands);
129    }
130}
131
132impl<T: Behavior> BehaviorHooks for T {}
133
134/// Common interface for querying [`Behavior`] state using a [`BehaviorRef`] or [`BehaviorMut`].
135pub trait BehaviorItem {
136    #[doc(hidden)]
137    type Behavior: Behavior;
138
139    /// Returns the current [`Behavior`] state.
140    fn current(&self) -> &Self::Behavior;
141
142    /// Returns the previous [`Behavior`] state in the stack.
143    ///
144    /// # Usage
145    ///
146    /// Note that this is **NOT** the previously active state.
147    /// Instead, this is the previous state which was active before the current one was started.
148    ///
149    /// To access the previously active state, handle [`Stop`] instead.
150    fn previous(&self) -> Option<&Self::Behavior>;
151
152    /// Returns the [`BehaviorIndex`] associated with the current [`Behavior`] state.
153    #[deprecated(since = "0.3.1", note = "use `current_index` instead")]
154    fn index(&self) -> BehaviorIndex {
155        self.current_index()
156    }
157
158    /// Returns the [`BehaviorIndex`] associated with the current [`Behavior`] state.
159    fn current_index(&self) -> BehaviorIndex;
160
161    /// Returns `true` if the given [`BehaviorIndex`] matches a state in this [`Behavior`] stack.
162    fn has_index(&self, index: BehaviorIndex) -> bool {
163        index <= self.current_index()
164    }
165
166    /// Returns an iterator over all ([`BehaviorIndex`], [`Behavior`]) pairs in the stack, including the current one.
167    ///
168    /// The iterator is ordered from the initial behavior (index = 0) to the current one.
169    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_;
170
171    /// Returns an iterator over all [`Behavior`] states in the stack, including the current one.
172    ///
173    /// The iterator is ordered from the initial behavior (index = 0) to the current one.
174    fn iter(&self) -> impl Iterator<Item = &Self::Behavior> + '_ {
175        self.enumerate().map(|(_, behavior)| behavior)
176    }
177
178    /// Returns a reference to the [`Behavior`] at the given [`BehaviorIndex`], if it exists.
179    fn get(&self, index: BehaviorIndex) -> Option<&Self::Behavior>;
180
181    /// Returns `true` if there is any pending [`Transition`] for this [`Behavior`].
182    ///
183    /// # Usage
184    ///
185    /// By design, only one transition is allowed per [`transition`](crate::transition::transition) cycle.
186    ///
187    /// The only exception to this rule is if the behavior is interrupted or reset where multiple states
188    /// may be stopped within a single cycle.
189    ///
190    /// If a transition is requested while another is pending, it would be overriden.
191    /// The transition helper methods [`start`](BehaviorMutItem::start), [`interrupt_start`](BehaviorMutItem::interrupt_start),
192    /// [`stop`](BehaviorMutItem::stop) and [`reset`](BehaviorMutItem::reset) all trigger a warning in this case.
193    ///
194    /// Because of this, this method is useful to avoid unintentional transition overrides.
195    fn has_transition(&self) -> bool;
196}
197
198/// Query data for a [`Behavior`].
199///
200/// # Usage
201///
202/// This provides a read-only reference to the current behavior state and all previous states in the stack.
203///
204/// Additionally, it provides methods to check for pending transitions ([`has_transition`](BehaviorRefItem::has_transition)),
205/// and the current behavior index ([`index`](BehaviorRefItem::index)).
206#[derive(QueryData)]
207pub struct BehaviorRef<T: Behavior> {
208    current: Ref<'static, T>,
209    memory: &'static Memory<T>,
210    transition: &'static Transition<T>,
211}
212
213impl<T: Behavior> BehaviorRef<T> {
214    /// Creates a new [`BehaviorRef`] item from an [`EntityRef`].
215    pub fn from_entity(entity: EntityRef) -> Option<BehaviorRefItem<T>> {
216        Some(BehaviorRefItem {
217            current: entity.get_ref::<T>()?,
218            memory: entity.get::<Memory<T>>()?,
219            transition: entity.get::<Transition<T>>()?,
220        })
221    }
222}
223
224impl<T: Behavior> BehaviorItem for BehaviorRefItem<'_, '_, T> {
225    type Behavior = T;
226
227    fn current(&self) -> &T {
228        &self.current
229    }
230
231    fn current_index(&self) -> BehaviorIndex {
232        BehaviorIndex(self.memory.len())
233    }
234
235    fn previous(&self) -> Option<&T> {
236        self.memory.last()
237    }
238
239    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
240        self.memory
241            .iter()
242            .enumerate()
243            .map(|(index, item)| (BehaviorIndex(index), item))
244            .chain(std::iter::once((self.current_index(), self.current())))
245    }
246
247    fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
248        if index == self.memory.stack.len() {
249            Some(self.current())
250        } else {
251            self.memory.get(index)
252        }
253    }
254
255    fn has_transition(&self) -> bool {
256        !self.transition.is_none()
257    }
258}
259
260impl<T: Behavior> Deref for BehaviorRefItem<'_, '_, T> {
261    type Target = T;
262
263    fn deref(&self) -> &Self::Target {
264        self.current()
265    }
266}
267
268impl<T: Behavior> AsRef<T> for BehaviorRefItem<'_, '_, T> {
269    fn as_ref(&self) -> &T {
270        &self.current
271    }
272}
273
274impl<T: Behavior> DetectChanges for BehaviorRefItem<'_, '_, T> {
275    fn is_added(&self) -> bool {
276        self.current.is_added()
277    }
278
279    fn is_changed(&self) -> bool {
280        self.current.is_changed()
281    }
282
283    fn last_changed(&self) -> Tick {
284        self.current.last_changed()
285    }
286
287    fn added(&self) -> Tick {
288        self.current.added()
289    }
290
291    fn changed_by(&self) -> MaybeLocation {
292        self.current.changed_by()
293    }
294
295    fn is_added_after(&self, other: Tick) -> bool {
296        self.current.is_added_after(other)
297    }
298
299    fn is_changed_after(&self, other: Tick) -> bool {
300        self.current.is_changed_after(other)
301    }
302}
303
304impl<T: Behavior> Index<BehaviorIndex> for BehaviorRefItem<'_, '_, T> {
305    type Output = T;
306
307    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
308        if index == self.memory.stack.len() {
309            self.current()
310        } else {
311            &self.memory[index]
312        }
313    }
314}
315
316/// Query data for a [`Behavior`] with mutable access.
317///
318/// # Usage
319///
320/// This provides a mutable reference to the current behavior state and all previous states in the stack.
321///
322/// See [`BehaviorRef`] for more details.
323#[derive(QueryData)]
324#[query_data(mutable)]
325pub struct BehaviorMut<T: Behavior> {
326    current: Mut<'static, T>,
327    memory: &'static mut Memory<T>,
328    transition: &'static mut Transition<T>,
329}
330
331impl<T: Behavior> BehaviorItem for BehaviorMutReadOnlyItem<'_, '_, T> {
332    type Behavior = T;
333
334    fn current(&self) -> &T {
335        &self.current
336    }
337
338    fn current_index(&self) -> BehaviorIndex {
339        BehaviorIndex(self.memory.len())
340    }
341
342    fn previous(&self) -> Option<&T> {
343        self.memory.last()
344    }
345
346    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
347        self.memory
348            .iter()
349            .enumerate()
350            .map(|(index, item)| (BehaviorIndex(index), item))
351            .chain(std::iter::once((self.current_index(), self.current())))
352    }
353
354    fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
355        if index == self.memory.stack.len() {
356            Some(self.current())
357        } else {
358            self.memory.get(index)
359        }
360    }
361
362    fn has_transition(&self) -> bool {
363        !self.transition.is_none()
364    }
365}
366
367impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, '_, T> {
368    type Target = T;
369
370    fn deref(&self) -> &Self::Target {
371        self.current()
372    }
373}
374
375impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, '_, T> {
376    fn as_ref(&self) -> &T {
377        self.current.as_ref()
378    }
379}
380
381impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, '_, T> {
382    fn is_added(&self) -> bool {
383        self.current.is_added()
384    }
385
386    fn is_changed(&self) -> bool {
387        self.current.is_changed()
388    }
389
390    fn last_changed(&self) -> Tick {
391        self.current.last_changed()
392    }
393
394    fn added(&self) -> Tick {
395        self.current.added()
396    }
397
398    fn changed_by(&self) -> MaybeLocation {
399        self.current.changed_by()
400    }
401
402    fn is_added_after(&self, other: Tick) -> bool {
403        self.current.is_added_after(other)
404    }
405
406    fn is_changed_after(&self, other: Tick) -> bool {
407        self.current.is_changed_after(other)
408    }
409}
410
411impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutReadOnlyItem<'_, '_, T> {
412    type Output = T;
413
414    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
415        if index == self.memory.stack.len() {
416            self.current()
417        } else {
418            &self.memory[index]
419        }
420    }
421}
422
423impl<T: Behavior> BehaviorItem for BehaviorMutItem<'_, '_, T> {
424    type Behavior = T;
425
426    fn current(&self) -> &T {
427        &self.current
428    }
429
430    fn current_index(&self) -> BehaviorIndex {
431        BehaviorIndex(self.memory.len())
432    }
433
434    fn previous(&self) -> Option<&T> {
435        self.memory.last()
436    }
437
438    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_ {
439        self.memory
440            .iter()
441            .enumerate()
442            .map(|(index, item)| (BehaviorIndex(index), item))
443            .chain(std::iter::once((self.current_index(), self.current())))
444    }
445
446    fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
447        if index == self.memory.stack.len() {
448            Some(self.current())
449        } else {
450            self.memory.get(index)
451        }
452    }
453
454    fn has_transition(&self) -> bool {
455        !self.transition.is_none()
456    }
457}
458
459impl<T: Behavior> BehaviorMutItem<'_, '_, T> {
460    /// Returns the current [`Behavior`] state as a mutable.
461    pub fn current_mut(&mut self) -> &mut T {
462        self.current.as_mut()
463    }
464
465    /// Returns the previous [`Behavior`] state as a mutable.
466    ///
467    /// See [`BehaviorRefItem::previous`] for more details.
468    pub fn previous_mut(&mut self) -> Option<&mut T> {
469        self.memory.last_mut()
470    }
471
472    /// Returns a mutable iterator over all [`Behavior`] states in the stack, including the current one.
473    ///
474    /// See [`BehaviorRefItem::iter`] for more details.
475    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
476        self.memory
477            .iter_mut()
478            .chain(std::iter::once(self.current.as_mut()))
479    }
480
481    /// Returns a mutable iterator over all ([`BehaviorIndex`], [`Behavior`]) pairs in the stack, including the current one.
482    ///
483    /// See [`BehaviorRefItem::enumerate`] for more details.
484    pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (BehaviorIndex, &mut T)> + '_ {
485        let current_index = self.current_index();
486        self.memory
487            .iter_mut()
488            .enumerate()
489            .map(|(index, item)| (BehaviorIndex(index), item))
490            .chain(std::iter::once((current_index, self.current.as_mut())))
491    }
492
493    /// Starts the given `next` behavior.
494    ///
495    /// This operation pushes the current behavior onto the stack and inserts the new behavior.
496    ///
497    /// Note that this will fail if the current behavior rejects `next` through [`Behavior::filter_next`].
498    /// See [`Error`] for details on how to handle transition failures.
499    #[track_caller]
500    pub fn start(&mut self, next: T) {
501        self.start_with_caller(next, MaybeLocation::caller());
502    }
503
504    /// Attempts to start the given `next` behavior if there are no pending transitions and the
505    /// current behavior allows it.
506    ///
507    /// Note that it's still possible for the transition to fail if the current behavior mutates
508    /// in such a way as to no longer allow the transition between the time this function is called
509    /// and when the [`transition`](crate::transition::transition) system runs.
510    ///
511    /// Do **NOT** use this method to react to transition failures.
512    /// See [`Error`] for details on how to correctly handle transition failures.
513    ///
514    /// # Usage
515    ///
516    /// This is similar to [`start`](BehaviorMutItem::start) but will return an error containing
517    /// the given `next` behavior if it fails.
518    ///
519    /// This is useful for fire-and-forget transitions where you don't want to override a
520    /// pending transition or may expect a transition failure.
521    ///
522    /// If multiple systems call this method before transition, only the first one will succeed.
523    #[track_caller]
524    pub fn try_start(&mut self, next: T) -> Result<(), T> {
525        if self.has_transition() || !self.filter_next(&next) {
526            return Err(next);
527        }
528
529        self.start_with_caller(next, MaybeLocation::caller());
530        Ok(())
531    }
532
533    fn start_with_caller(&mut self, next: T, caller: MaybeLocation) {
534        self.set_transition(Next(next), caller);
535    }
536
537    /// Interrupts the current behavior and starts the given `next` behavior.
538    ///
539    /// This operation stops all behaviors which yield to the new behavior and pushes it onto the stack.
540    /// See [`Behavior::filter_yield`] for details on how to define how states yield to each other.
541    ///
542    /// This also removes any remaining [`TransitionSequence`] steps.
543    ///
544    /// The initial behavior is never allowed to yield.
545    ///
546    /// Note that this will fail if the first non-yielding behavior rejects `next` through [`Behavior::filter_next`].
547    /// See [`Error`] for details on how to handle transition failures.
548    #[track_caller]
549    pub fn interrupt_start(&mut self, next: T) {
550        self.interrupt_start_with_caller(next, MaybeLocation::caller());
551    }
552
553    /// Attempts to interrupt the current behavior and start the given `next` behavior.
554    ///
555    /// This is similar to [`interrupt_start`](BehaviorMutItem::interrupt_start) but will fail if there is a pending transition.
556    #[track_caller]
557    pub fn try_interrupt_start(&mut self, next: T) -> Result<(), T> {
558        if self.has_transition() {
559            return Err(next);
560        }
561
562        self.interrupt_start_with_caller(next, MaybeLocation::caller());
563        Ok(())
564    }
565
566    fn interrupt_start_with_caller(&mut self, next: T, caller: MaybeLocation) {
567        self.set_transition(Interrupt(Interruption::Start(next)), caller);
568    }
569
570    /// Stops all behaviors above and including the given [`BehaviorIndex`].
571    ///
572    /// This also removes any remaining [`TransitionSequence`] steps.
573    ///
574    /// The initial behavior is never allowed to yield.
575    #[track_caller]
576    pub fn interrupt_stop(&mut self, index: BehaviorIndex) {
577        self.interrupt_resume_with_caller(index.previous().unwrap(), MaybeLocation::caller());
578    }
579
580    /// Attempts to stop all behaviors above and including the given [`BehaviorIndex`].
581    ///
582    /// This is similar to [`interrupt_stop`](BehaviorMutItem::interrupt_stop) but will fail if:
583    /// - There is a pending transition
584    /// - The given `index` is the initial behavior
585    /// - The given `index` is not in the stack
586    #[track_caller]
587    pub fn try_interrupt_stop(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
588        if self.has_transition() || !self.has_index(index) {
589            return Err(index);
590        }
591
592        let Some(previous_index) = index.previous() else {
593            return Err(index);
594        };
595
596        self.interrupt_resume_with_caller(previous_index, MaybeLocation::caller());
597        Ok(())
598    }
599
600    /// Stops all behaviors above the given [`BehaviorIndex`] and resume the behavior at that index.
601    ///
602    /// This also removes any remaining [`TransitionSequence`] steps.
603    #[track_caller]
604    pub fn interrupt_resume(&mut self, index: BehaviorIndex) {
605        self.interrupt_resume_with_caller(index, MaybeLocation::caller());
606    }
607
608    /// Attempts to stop all behaviors above the given [`BehaviorIndex`] and resume the behavior at that index.
609    ///
610    /// This is similar to [`interrupt_resume`](BehaviorMutItem::interrupt_resume) but will fail if:
611    /// - There is a pending transition
612    /// - The given `index` is not in the stack
613    #[track_caller]
614    pub fn try_interrupt_resume(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
615        if self.has_transition() || !self.has_index(index) {
616            return Err(index);
617        }
618
619        self.interrupt_resume_with_caller(index, MaybeLocation::caller());
620        Ok(())
621    }
622
623    fn interrupt_resume_with_caller(&mut self, index: BehaviorIndex, caller: MaybeLocation) {
624        self.set_transition(Interrupt(Interruption::Resume(index)), caller);
625    }
626
627    /// Stops the current behavior.
628    ///
629    /// This operation pops the current behavior off the stack and resumes the previous behavior.
630    ///
631    /// Note that this will fail if the current behavior is the initial behavior.
632    /// See [`Error`] for details on how to handle transition failures.
633    #[track_caller]
634    pub fn stop(&mut self) {
635        self.stop_with_caller(MaybeLocation::caller());
636    }
637
638    /// Attempts to stop the current behavior.
639    ///
640    /// This is similar to [`stop`](BehaviorMutItem::stop) but will fail if:
641    /// - There is a pending transition
642    /// - The current behavior is the initial behavior
643    #[track_caller]
644    pub fn try_stop(&mut self) -> bool {
645        if self.has_transition() || self.memory.is_empty() {
646            return false;
647        }
648
649        self.stop_with_caller(MaybeLocation::caller());
650        true
651    }
652
653    fn stop_with_caller(&mut self, caller: MaybeLocation) {
654        self.set_transition(Previous, caller);
655    }
656
657    /// Stops the current and all previous behaviors and resumes the initial behavior.
658    ///
659    /// This operation clears the stack and resumes the initial behavior. It can never fail.
660    /// If the stack is empty (i.e. initial behavior), it does nothing.
661    #[track_caller]
662    pub fn reset(&mut self) {
663        self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
664    }
665
666    /// Attempts to reset the current behavior.
667    ///
668    /// This is similar to [`reset`](BehaviorMutItem::reset) but will fail if there is a pending transition.
669    #[track_caller]
670    pub fn try_reset(&mut self) -> bool {
671        if self.has_transition() {
672            return false;
673        }
674
675        self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
676        true
677    }
678
679    fn set_transition(&mut self, transition: Transition<T>, caller: MaybeLocation) {
680        let previous = replace(self.transition.as_mut(), transition);
681        if !previous.is_none() {
682            warn!(
683                "transition override ({caller})): {previous:?} -> {:?}",
684                *self.transition
685            );
686        }
687    }
688
689    fn push(
690        &mut self,
691        instance: Instance<T>,
692        mut next: T,
693        initial: bool,
694        commands: &mut Commands,
695    ) -> bool {
696        if self.filter_next(&next) {
697            let previous = {
698                swap(self.current.as_mut(), &mut next);
699                next
700            };
701            self.invoke_start(Some(&previous), commands.instance(instance));
702            let index = self.memory.len();
703            if previous.is_resumable() {
704                let next_index = index + 1;
705                debug!(
706                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{next_index})",
707                    *self.current
708                );
709
710                previous.invoke_pause(&self.current, commands.instance(instance));
711
712                commands.queue(move |world: &mut World| {
713                    world.trigger_with(
714                        Pause {
715                            instance,
716                            index: BehaviorIndex(index),
717                        },
718                        EntityTrigger,
719                    );
720                    world.trigger_with(
721                        Start {
722                            instance,
723                            index: BehaviorIndex(next_index),
724                            initial,
725                        },
726                        EntityTrigger,
727                    );
728                    world.trigger_with(
729                        Activate {
730                            instance,
731                            index: BehaviorIndex(next_index),
732                            resume: false,
733                            initial,
734                        },
735                        EntityTrigger,
736                    );
737                });
738
739                self.memory.push(previous);
740            } else {
741                debug!(
742                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
743                    *self.current
744                );
745
746                previous.invoke_stop(&self.current, commands.instance(instance));
747
748                commands.queue(move |world: &mut World| {
749                    world.trigger_with(
750                        Stop {
751                            instance,
752                            index: BehaviorIndex(index),
753                            behavior: previous,
754                            interrupt: false,
755                        },
756                        EntityTrigger,
757                    );
758                    world.trigger_with(
759                        Start {
760                            instance,
761                            index: BehaviorIndex(index),
762                            initial,
763                        },
764                        EntityTrigger,
765                    );
766                    world.trigger_with(
767                        Activate {
768                            instance,
769                            index: BehaviorIndex(index),
770                            resume: false,
771                            initial,
772                        },
773                        EntityTrigger,
774                    );
775                })
776            }
777            true
778        } else {
779            warn!(
780                "{instance:?}: transition {:?} -> {next:?} is not allowed",
781                *self.current
782            );
783
784            commands.queue(move |world: &mut World| {
785                world.trigger_with(
786                    Error {
787                        instance,
788                        error: TransitionError::RejectedNext(next),
789                    },
790                    EntityTrigger,
791                );
792            });
793
794            false
795        }
796    }
797
798    fn interrupt(&mut self, instance: Instance<T>, next: T, commands: &mut Commands) {
799        while self.filter_yield(&next) && !self.memory.is_empty() {
800            let index = self.memory.len();
801            if let Some(mut next) = self.memory.pop() {
802                let previous = {
803                    swap(self.current.as_mut(), &mut next);
804                    next
805                };
806                debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
807                previous.invoke_stop(&self.current, commands.instance(instance));
808
809                commands.queue(move |world: &mut World| {
810                    world.trigger_with(
811                        Stop {
812                            instance,
813                            index: BehaviorIndex(index),
814                            behavior: previous,
815                            interrupt: true,
816                        },
817                        EntityTrigger,
818                    );
819                });
820            }
821        }
822
823        self.push(instance, next, false, commands);
824    }
825
826    fn pop(&mut self, instance: Instance<T>, commands: &mut Commands) -> bool {
827        let index = self.memory.len();
828
829        if let Some(mut next) = self.memory.pop() {
830            let next_index = self.memory.len();
831            debug!(
832                "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
833                *self.current
834            );
835            let previous = {
836                swap(self.current.as_mut(), &mut next);
837                next
838            };
839            self.invoke_resume(&previous, commands.instance(instance));
840            previous.invoke_stop(&self.current, commands.instance(instance));
841
842            commands.queue(move |world: &mut World| {
843                world.trigger_with(
844                    Stop {
845                        instance,
846                        index: BehaviorIndex(index),
847                        behavior: previous,
848                        interrupt: false,
849                    },
850                    EntityTrigger,
851                );
852                world.trigger_with(
853                    Resume {
854                        instance,
855                        index: BehaviorIndex(next_index),
856                    },
857                    EntityTrigger,
858                );
859                world.trigger_with(
860                    Activate {
861                        instance,
862                        index: BehaviorIndex(next_index),
863                        resume: true,
864                        initial: false,
865                    },
866                    EntityTrigger,
867                );
868            });
869            true
870        } else {
871            warn!(
872                "{instance:?}: transition {:?} -> None is not allowed",
873                *self.current
874            );
875
876            commands.queue(move |world: &mut World| {
877                world.trigger_with(
878                    Error {
879                        instance,
880                        error: TransitionError::<T>::NoPrevious,
881                    },
882                    EntityTrigger,
883                );
884            });
885
886            false
887        }
888    }
889
890    fn clear(&mut self, instance: Instance<T>, index: BehaviorIndex, commands: &mut Commands) {
891        // Stop all states except the one above the given index
892        while self.current_index() > index.next() {
893            let index = self.memory.len();
894            let previous = self.memory.pop().unwrap();
895            let next = self.memory.last().unwrap();
896            debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
897            previous.invoke_stop(next, commands.instance(instance));
898
899            commands.queue(move |world: &mut World| {
900                world.trigger_with(
901                    Stop {
902                        instance,
903                        index: BehaviorIndex(index),
904                        behavior: previous,
905                        interrupt: true,
906                    },
907                    EntityTrigger,
908                );
909            });
910        }
911
912        // Pop the state above the given index
913        self.pop(instance, commands);
914    }
915}
916
917impl<T: Behavior> Deref for BehaviorMutItem<'_, '_, T> {
918    type Target = T;
919
920    fn deref(&self) -> &Self::Target {
921        self.current()
922    }
923}
924
925impl<T: Behavior> DerefMut for BehaviorMutItem<'_, '_, T> {
926    fn deref_mut(&mut self) -> &mut Self::Target {
927        self.current_mut()
928    }
929}
930
931impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, '_, T> {
932    fn is_added(&self) -> bool {
933        self.current.is_added()
934    }
935
936    fn is_changed(&self) -> bool {
937        self.current.is_changed()
938    }
939
940    fn last_changed(&self) -> Tick {
941        self.current.last_changed()
942    }
943
944    fn added(&self) -> Tick {
945        self.current.added()
946    }
947
948    fn changed_by(&self) -> MaybeLocation {
949        self.current.changed_by()
950    }
951
952    fn is_added_after(&self, other: Tick) -> bool {
953        self.current.is_added_after(other)
954    }
955
956    fn is_changed_after(&self, other: Tick) -> bool {
957        self.current.is_changed_after(other)
958    }
959}
960
961impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, '_, T> {
962    type Inner = T;
963
964    fn set_changed(&mut self) {
965        self.current.set_changed()
966    }
967
968    fn set_last_changed(&mut self, last_changed: Tick) {
969        self.current.set_last_changed(last_changed)
970    }
971
972    fn bypass_change_detection(&mut self) -> &mut Self::Inner {
973        self.current.bypass_change_detection()
974    }
975
976    fn set_added(&mut self) {
977        self.current.set_added()
978    }
979
980    fn set_last_added(&mut self, last_added: Tick) {
981        self.current.set_last_added(last_added)
982    }
983}
984
985impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, '_, T> {
986    fn as_ref(&self) -> &T {
987        self.current.as_ref()
988    }
989}
990
991impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, '_, T> {
992    fn as_mut(&mut self) -> &mut T {
993        self.current.as_mut()
994    }
995}
996
997impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
998    type Output = T;
999
1000    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
1001        if index == self.memory.stack.len() {
1002            self.current()
1003        } else {
1004            &self.memory[index]
1005        }
1006    }
1007}
1008
1009impl<T: Behavior> IndexMut<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
1010    fn index_mut(&mut self, BehaviorIndex(index): BehaviorIndex) -> &mut Self::Output {
1011        if index == self.memory.stack.len() {
1012            self.current_mut()
1013        } else {
1014            &mut self.memory[index]
1015        }
1016    }
1017}
1018
1019/// A numeric index which represents the position of a [`Behavior`] in the stack.
1020///
1021/// This index may be used to uniquely identify each behavior state.
1022/// The initial behavior always has the index of `0`, and the current behavior always has the highest index (length of the stack).
1023#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Reflect)]
1024pub struct BehaviorIndex(usize);
1025
1026impl BehaviorIndex {
1027    /// Returns the index of the initial behavior. This is always `0`.
1028    pub fn initial() -> Self {
1029        Self(0)
1030    }
1031
1032    /// Returns the index of the behavior before this one, if exists.
1033    pub fn previous(self) -> Option<Self> {
1034        if self == BehaviorIndex::initial() {
1035            return None;
1036        }
1037
1038        Some(Self(self.0.saturating_sub(1)))
1039    }
1040
1041    fn next(self) -> Self {
1042        Self(self.0.saturating_add(1))
1043    }
1044}
1045
1046#[derive(Component, Deref, DerefMut, Reflect)]
1047#[reflect(Component)]
1048struct Memory<T: Behavior> {
1049    stack: Vec<T>,
1050}
1051
1052impl<T: Behavior> Default for Memory<T> {
1053    fn default() -> Self {
1054        Self {
1055            stack: Vec::default(),
1056        }
1057    }
1058}
1059
1060/// A convenient macro for implementation of [`Behavior::filter_next`].
1061///
1062/// # Usage
1063/// For any given pair of states `curr` and `next`, this match expands into a match arm such that:
1064/// ```rust,ignore
1065/// match curr {
1066///     From => matches!(next, To)
1067/// }
1068/// ```
1069/// where `From` is the current possible state, and `To` is the next allowed state.
1070///
1071/// # Example
1072///
1073/// ```rust
1074/// # use bevy::prelude::*;
1075/// # use moonshine_behavior::prelude::*;
1076/// #[derive(Component, Debug)]
1077/// enum Soldier {
1078///     Idle,
1079///     Crouch,
1080///     Fire,
1081///     Sprint,
1082///     Jump,
1083/// }
1084///
1085/// impl Behavior for Soldier {
1086///     fn filter_next(&self, next: &Self) -> bool {
1087///         use Soldier::*;
1088///         match_next! {
1089///             self => next,
1090///             Idle => Crouch | Sprint | Fire | Jump,
1091///             Crouch => Sprint | Fire,
1092///             Sprint => Jump,
1093///         }
1094///     }
1095/// }
1096///
1097/// # assert!(Soldier::Idle.filter_next(&Soldier::Crouch));
1098/// # assert!(!Soldier::Sprint.filter_next(&Soldier::Fire));
1099/// ```
1100#[macro_export]
1101macro_rules! match_next {
1102    { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
1103        match $curr {
1104            $(
1105                $from => matches!($next, $to),
1106            )*
1107            #[allow(unreachable_patterns)]
1108            _ => false,
1109        }
1110    };
1111}