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;
38use bevy_ecs::component::{Mutable, Tick};
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
296impl<T: Behavior> Index<BehaviorIndex> for BehaviorRefItem<'_, '_, T> {
297    type Output = T;
298
299    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
300        if index == self.memory.stack.len() {
301            self.current()
302        } else {
303            &self.memory[index]
304        }
305    }
306}
307
308/// Query data for a [`Behavior`] with mutable access.
309///
310/// # Usage
311///
312/// This provides a mutable reference to the current behavior state and all previous states in the stack.
313///
314/// See [`BehaviorRef`] for more details.
315#[derive(QueryData)]
316#[query_data(mutable)]
317pub struct BehaviorMut<T: Behavior> {
318    current: Mut<'static, T>,
319    memory: &'static mut Memory<T>,
320    transition: &'static mut Transition<T>,
321}
322
323impl<T: Behavior> BehaviorItem for BehaviorMutReadOnlyItem<'_, '_, T> {
324    type Behavior = T;
325
326    fn current(&self) -> &T {
327        &self.current
328    }
329
330    fn current_index(&self) -> BehaviorIndex {
331        BehaviorIndex(self.memory.len())
332    }
333
334    fn previous(&self) -> Option<&T> {
335        self.memory.last()
336    }
337
338    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &T)> + '_ {
339        self.memory
340            .iter()
341            .enumerate()
342            .map(|(index, item)| (BehaviorIndex(index), item))
343            .chain(std::iter::once((self.current_index(), self.current())))
344    }
345
346    fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
347        if index == self.memory.stack.len() {
348            Some(self.current())
349        } else {
350            self.memory.get(index)
351        }
352    }
353
354    fn has_transition(&self) -> bool {
355        !self.transition.is_none()
356    }
357}
358
359impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, '_, T> {
360    type Target = T;
361
362    fn deref(&self) -> &Self::Target {
363        self.current()
364    }
365}
366
367impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, '_, T> {
368    fn as_ref(&self) -> &T {
369        self.current.as_ref()
370    }
371}
372
373impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, '_, T> {
374    fn is_added(&self) -> bool {
375        self.current.is_added()
376    }
377
378    fn is_changed(&self) -> bool {
379        self.current.is_changed()
380    }
381
382    fn last_changed(&self) -> Tick {
383        self.current.last_changed()
384    }
385
386    fn added(&self) -> Tick {
387        self.current.added()
388    }
389
390    fn changed_by(&self) -> MaybeLocation {
391        self.current.changed_by()
392    }
393}
394
395impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutReadOnlyItem<'_, '_, T> {
396    type Output = T;
397
398    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
399        if index == self.memory.stack.len() {
400            self.current()
401        } else {
402            &self.memory[index]
403        }
404    }
405}
406
407impl<T: Behavior> BehaviorItem for BehaviorMutItem<'_, '_, T> {
408    type Behavior = T;
409
410    fn current(&self) -> &T {
411        &self.current
412    }
413
414    fn current_index(&self) -> BehaviorIndex {
415        BehaviorIndex(self.memory.len())
416    }
417
418    fn previous(&self) -> Option<&T> {
419        self.memory.last()
420    }
421
422    fn enumerate(&self) -> impl Iterator<Item = (BehaviorIndex, &Self::Behavior)> + '_ {
423        self.memory
424            .iter()
425            .enumerate()
426            .map(|(index, item)| (BehaviorIndex(index), item))
427            .chain(std::iter::once((self.current_index(), self.current())))
428    }
429
430    fn get(&self, BehaviorIndex(index): BehaviorIndex) -> Option<&T> {
431        if index == self.memory.stack.len() {
432            Some(self.current())
433        } else {
434            self.memory.get(index)
435        }
436    }
437
438    fn has_transition(&self) -> bool {
439        !self.transition.is_none()
440    }
441}
442
443impl<T: Behavior> BehaviorMutItem<'_, '_, T> {
444    /// Returns the current [`Behavior`] state as a mutable.
445    pub fn current_mut(&mut self) -> &mut T {
446        self.current.as_mut()
447    }
448
449    /// Returns the previous [`Behavior`] state as a mutable.
450    ///
451    /// See [`BehaviorRefItem::previous`] for more details.
452    pub fn previous_mut(&mut self) -> Option<&mut T> {
453        self.memory.last_mut()
454    }
455
456    /// Returns a mutable iterator over all [`Behavior`] states in the stack, including the current one.
457    ///
458    /// See [`BehaviorRefItem::iter`] for more details.
459    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
460        self.memory
461            .iter_mut()
462            .chain(std::iter::once(self.current.as_mut()))
463    }
464
465    /// Returns a mutable iterator over all ([`BehaviorIndex`], [`Behavior`]) pairs in the stack, including the current one.
466    ///
467    /// See [`BehaviorRefItem::enumerate`] for more details.
468    pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (BehaviorIndex, &mut T)> + '_ {
469        let current_index = self.current_index();
470        self.memory
471            .iter_mut()
472            .enumerate()
473            .map(|(index, item)| (BehaviorIndex(index), item))
474            .chain(std::iter::once((current_index, self.current.as_mut())))
475    }
476
477    /// Starts the given `next` behavior.
478    ///
479    /// This operation pushes the current behavior onto the stack and inserts the new behavior.
480    ///
481    /// Note that this will fail if the current behavior rejects `next` through [`Behavior::filter_next`].
482    /// See [`Error`] for details on how to handle transition failures.
483    #[track_caller]
484    pub fn start(&mut self, next: T) {
485        self.start_with_caller(next, MaybeLocation::caller());
486    }
487
488    /// Attempts to start the given `next` behavior if there are no pending transitions and the
489    /// current behavior allows it.
490    ///
491    /// Note that it's still possible for the transition to fail if the current behavior mutates
492    /// in such a way as to no longer allow the transition between the time this function is called
493    /// and when the [`transition`](crate::transition::transition) system runs.
494    ///
495    /// Do **NOT** use this method to react to transition failures.
496    /// See [`Error`] for details on how to correctly handle transition failures.
497    ///
498    /// # Usage
499    ///
500    /// This is similar to [`start`](BehaviorMutItem::start) but will return an error containing
501    /// the given `next` behavior if it fails.
502    ///
503    /// This is useful for fire-and-forget transitions where you don't want to override a
504    /// pending transition or may expect a transition failure.
505    ///
506    /// If multiple systems call this method before transition, only the first one will succeed.
507    #[track_caller]
508    pub fn try_start(&mut self, next: T) -> Result<(), T> {
509        if self.has_transition() || !self.filter_next(&next) {
510            return Err(next);
511        }
512
513        self.start_with_caller(next, MaybeLocation::caller());
514        Ok(())
515    }
516
517    fn start_with_caller(&mut self, next: T, caller: MaybeLocation) {
518        self.set_transition(Next(next), caller);
519    }
520
521    /// Interrupts the current behavior and starts the given `next` behavior.
522    ///
523    /// This operation stops all behaviors which yield to the new behavior and pushes it onto the stack.
524    /// See [`Behavior::filter_yield`] for details on how to define how states yield to each other.
525    ///
526    /// This also removes any remaining [`TransitionSequence`] steps.
527    ///
528    /// The initial behavior is never allowed to yield.
529    ///
530    /// Note that this will fail if the first non-yielding behavior rejects `next` through [`Behavior::filter_next`].
531    /// See [`Error`] for details on how to handle transition failures.
532    #[track_caller]
533    pub fn interrupt_start(&mut self, next: T) {
534        self.interrupt_start_with_caller(next, MaybeLocation::caller());
535    }
536
537    /// Attempts to interrupt the current behavior and start the given `next` behavior.
538    ///
539    /// This is similar to [`interrupt_start`](BehaviorMutItem::interrupt_start) but will fail if there is a pending transition.
540    #[track_caller]
541    pub fn try_interrupt_start(&mut self, next: T) -> Result<(), T> {
542        if self.has_transition() {
543            return Err(next);
544        }
545
546        self.interrupt_start_with_caller(next, MaybeLocation::caller());
547        Ok(())
548    }
549
550    fn interrupt_start_with_caller(&mut self, next: T, caller: MaybeLocation) {
551        self.set_transition(Interrupt(Interruption::Start(next)), caller);
552    }
553
554    /// Stops all behaviors above and including the given [`BehaviorIndex`].
555    ///
556    /// This also removes any remaining [`TransitionSequence`] steps.
557    ///
558    /// The initial behavior is never allowed to yield.
559    #[track_caller]
560    pub fn interrupt_stop(&mut self, index: BehaviorIndex) {
561        self.interrupt_resume_with_caller(index.previous().unwrap(), MaybeLocation::caller());
562    }
563
564    /// Attempts to stop all behaviors above and including the given [`BehaviorIndex`].
565    ///
566    /// This is similar to [`interrupt_stop`](BehaviorMutItem::interrupt_stop) but will fail if:
567    /// - There is a pending transition
568    /// - The given `index` is the initial behavior
569    /// - The given `index` is not in the stack
570    #[track_caller]
571    pub fn try_interrupt_stop(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
572        if self.has_transition() || !self.has_index(index) {
573            return Err(index);
574        }
575
576        let Some(previous_index) = index.previous() else {
577            return Err(index);
578        };
579
580        self.interrupt_resume_with_caller(previous_index, MaybeLocation::caller());
581        Ok(())
582    }
583
584    /// Stops all behaviors above the given [`BehaviorIndex`] and resume the behavior at that index.
585    ///
586    /// This also removes any remaining [`TransitionSequence`] steps.
587    #[track_caller]
588    pub fn interrupt_resume(&mut self, index: BehaviorIndex) {
589        self.interrupt_resume_with_caller(index, MaybeLocation::caller());
590    }
591
592    /// Attempts to stop all behaviors above the given [`BehaviorIndex`] and resume the behavior at that index.
593    ///
594    /// This is similar to [`interrupt_resume`](BehaviorMutItem::interrupt_resume) but will fail if:
595    /// - There is a pending transition
596    /// - The given `index` is not in the stack
597    #[track_caller]
598    pub fn try_interrupt_resume(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
599        if self.has_transition() || !self.has_index(index) {
600            return Err(index);
601        }
602
603        self.interrupt_resume_with_caller(index, MaybeLocation::caller());
604        Ok(())
605    }
606
607    fn interrupt_resume_with_caller(&mut self, index: BehaviorIndex, caller: MaybeLocation) {
608        self.set_transition(Interrupt(Interruption::Resume(index)), caller);
609    }
610
611    /// Stops the current behavior.
612    ///
613    /// This operation pops the current behavior off the stack and resumes the previous behavior.
614    ///
615    /// Note that this will fail if the current behavior is the initial behavior.
616    /// See [`Error`] for details on how to handle transition failures.
617    #[track_caller]
618    pub fn stop(&mut self) {
619        self.stop_with_caller(MaybeLocation::caller());
620    }
621
622    /// Attempts to stop the current behavior.
623    ///
624    /// This is similar to [`stop`](BehaviorMutItem::stop) but will fail if:
625    /// - There is a pending transition
626    /// - The current behavior is the initial behavior
627    #[track_caller]
628    pub fn try_stop(&mut self) -> bool {
629        if self.has_transition() || self.memory.is_empty() {
630            return false;
631        }
632
633        self.stop_with_caller(MaybeLocation::caller());
634        true
635    }
636
637    fn stop_with_caller(&mut self, caller: MaybeLocation) {
638        self.set_transition(Previous, caller);
639    }
640
641    /// Stops the current and all previous behaviors and resumes the initial behavior.
642    ///
643    /// This operation clears the stack and resumes the initial behavior. It can never fail.
644    /// If the stack is empty (i.e. initial behavior), it does nothing.
645    #[track_caller]
646    pub fn reset(&mut self) {
647        self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
648    }
649
650    /// Attempts to reset the current behavior.
651    ///
652    /// This is similar to [`reset`](BehaviorMutItem::reset) but will fail if there is a pending transition.
653    #[track_caller]
654    pub fn try_reset(&mut self) -> bool {
655        if self.has_transition() {
656            return false;
657        }
658
659        self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
660        true
661    }
662
663    fn set_transition(&mut self, transition: Transition<T>, caller: MaybeLocation) {
664        let previous = replace(self.transition.as_mut(), transition);
665        if !previous.is_none() {
666            warn!(
667                "transition override ({caller})): {previous:?} -> {:?}",
668                *self.transition
669            );
670        }
671    }
672
673    fn push(
674        &mut self,
675        instance: Instance<T>,
676        mut next: T,
677        initial: bool,
678        commands: &mut Commands,
679    ) -> bool {
680        if self.filter_next(&next) {
681            let previous = {
682                swap(self.current.as_mut(), &mut next);
683                next
684            };
685            self.invoke_start(Some(&previous), commands.instance(instance));
686            let index = self.memory.len();
687            if previous.is_resumable() {
688                let next_index = index + 1;
689                debug!(
690                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{next_index})",
691                    *self.current
692                );
693
694                previous.invoke_pause(&self.current, commands.instance(instance));
695
696                commands.queue(move |world: &mut World| {
697                    world.trigger_with(
698                        Pause {
699                            instance,
700                            index: BehaviorIndex(index),
701                        },
702                        EntityTrigger,
703                    );
704                    world.trigger_with(
705                        Start {
706                            instance,
707                            index: BehaviorIndex(next_index),
708                            initial,
709                        },
710                        EntityTrigger,
711                    );
712                    world.trigger_with(
713                        Activate {
714                            instance,
715                            index: BehaviorIndex(next_index),
716                            resume: false,
717                            initial,
718                        },
719                        EntityTrigger,
720                    );
721                });
722
723                self.memory.push(previous);
724            } else {
725                debug!(
726                    "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
727                    *self.current
728                );
729
730                previous.invoke_stop(&self.current, commands.instance(instance));
731
732                commands.queue(move |world: &mut World| {
733                    world.trigger_with(
734                        Stop {
735                            instance,
736                            index: BehaviorIndex(index),
737                            behavior: previous,
738                            interrupt: false,
739                        },
740                        EntityTrigger,
741                    );
742                    world.trigger_with(
743                        Start {
744                            instance,
745                            index: BehaviorIndex(index),
746                            initial,
747                        },
748                        EntityTrigger,
749                    );
750                    world.trigger_with(
751                        Activate {
752                            instance,
753                            index: BehaviorIndex(index),
754                            resume: false,
755                            initial,
756                        },
757                        EntityTrigger,
758                    );
759                })
760            }
761            true
762        } else {
763            warn!(
764                "{instance:?}: transition {:?} -> {next:?} is not allowed",
765                *self.current
766            );
767
768            commands.queue(move |world: &mut World| {
769                world.trigger_with(
770                    Error {
771                        instance,
772                        error: TransitionError::RejectedNext(next),
773                    },
774                    EntityTrigger,
775                );
776            });
777
778            false
779        }
780    }
781
782    fn interrupt(&mut self, instance: Instance<T>, next: T, commands: &mut Commands) {
783        while self.filter_yield(&next) && !self.memory.is_empty() {
784            let index = self.memory.len();
785            if let Some(mut next) = self.memory.pop() {
786                let previous = {
787                    swap(self.current.as_mut(), &mut next);
788                    next
789                };
790                debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
791                previous.invoke_stop(&self.current, commands.instance(instance));
792
793                commands.queue(move |world: &mut World| {
794                    world.trigger_with(
795                        Stop {
796                            instance,
797                            index: BehaviorIndex(index),
798                            behavior: previous,
799                            interrupt: true,
800                        },
801                        EntityTrigger,
802                    );
803                });
804            }
805        }
806
807        self.push(instance, next, false, commands);
808    }
809
810    fn pop(&mut self, instance: Instance<T>, commands: &mut Commands) -> bool {
811        let index = self.memory.len();
812
813        if let Some(mut next) = self.memory.pop() {
814            let next_index = self.memory.len();
815            debug!(
816                "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
817                *self.current
818            );
819            let previous = {
820                swap(self.current.as_mut(), &mut next);
821                next
822            };
823            self.invoke_resume(&previous, commands.instance(instance));
824            previous.invoke_stop(&self.current, commands.instance(instance));
825
826            commands.queue(move |world: &mut World| {
827                world.trigger_with(
828                    Stop {
829                        instance,
830                        index: BehaviorIndex(index),
831                        behavior: previous,
832                        interrupt: false,
833                    },
834                    EntityTrigger,
835                );
836                world.trigger_with(
837                    Resume {
838                        instance,
839                        index: BehaviorIndex(next_index),
840                    },
841                    EntityTrigger,
842                );
843                world.trigger_with(
844                    Activate {
845                        instance,
846                        index: BehaviorIndex(next_index),
847                        resume: true,
848                        initial: false,
849                    },
850                    EntityTrigger,
851                );
852            });
853            true
854        } else {
855            warn!(
856                "{instance:?}: transition {:?} -> None is not allowed",
857                *self.current
858            );
859
860            commands.queue(move |world: &mut World| {
861                world.trigger_with(
862                    Error {
863                        instance,
864                        error: TransitionError::<T>::NoPrevious,
865                    },
866                    EntityTrigger,
867                );
868            });
869
870            false
871        }
872    }
873
874    fn clear(&mut self, instance: Instance<T>, index: BehaviorIndex, commands: &mut Commands) {
875        // Stop all states except the one above the given index
876        while self.current_index() > index.next() {
877            let index = self.memory.len();
878            let previous = self.memory.pop().unwrap();
879            let next = self.memory.last().unwrap();
880            debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
881            previous.invoke_stop(next, commands.instance(instance));
882
883            commands.queue(move |world: &mut World| {
884                world.trigger_with(
885                    Stop {
886                        instance,
887                        index: BehaviorIndex(index),
888                        behavior: previous,
889                        interrupt: true,
890                    },
891                    EntityTrigger,
892                );
893            });
894        }
895
896        // Pop the state above the given index
897        self.pop(instance, commands);
898    }
899}
900
901impl<T: Behavior> Deref for BehaviorMutItem<'_, '_, T> {
902    type Target = T;
903
904    fn deref(&self) -> &Self::Target {
905        self.current()
906    }
907}
908
909impl<T: Behavior> DerefMut for BehaviorMutItem<'_, '_, T> {
910    fn deref_mut(&mut self) -> &mut Self::Target {
911        self.current_mut()
912    }
913}
914
915impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, '_, T> {
916    fn is_added(&self) -> bool {
917        self.current.is_added()
918    }
919
920    fn is_changed(&self) -> bool {
921        self.current.is_changed()
922    }
923
924    fn last_changed(&self) -> Tick {
925        self.current.last_changed()
926    }
927
928    fn added(&self) -> Tick {
929        self.current.added()
930    }
931
932    fn changed_by(&self) -> MaybeLocation {
933        self.current.changed_by()
934    }
935}
936
937impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, '_, T> {
938    type Inner = T;
939
940    fn set_changed(&mut self) {
941        self.current.set_changed()
942    }
943
944    fn set_last_changed(&mut self, last_changed: Tick) {
945        self.current.set_last_changed(last_changed)
946    }
947
948    fn bypass_change_detection(&mut self) -> &mut Self::Inner {
949        self.current.bypass_change_detection()
950    }
951
952    fn set_added(&mut self) {
953        self.current.set_added()
954    }
955
956    fn set_last_added(&mut self, last_added: Tick) {
957        self.current.set_last_added(last_added)
958    }
959}
960
961impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, '_, T> {
962    fn as_ref(&self) -> &T {
963        self.current.as_ref()
964    }
965}
966
967impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, '_, T> {
968    fn as_mut(&mut self) -> &mut T {
969        self.current.as_mut()
970    }
971}
972
973impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
974    type Output = T;
975
976    fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
977        if index == self.memory.stack.len() {
978            self.current()
979        } else {
980            &self.memory[index]
981        }
982    }
983}
984
985impl<T: Behavior> IndexMut<BehaviorIndex> for BehaviorMutItem<'_, '_, T> {
986    fn index_mut(&mut self, BehaviorIndex(index): BehaviorIndex) -> &mut Self::Output {
987        if index == self.memory.stack.len() {
988            self.current_mut()
989        } else {
990            &mut self.memory[index]
991        }
992    }
993}
994
995/// A numeric index which represents the position of a [`Behavior`] in the stack.
996///
997/// This index may be used to uniquely identify each behavior state.
998/// The initial behavior always has the index of `0`, and the current behavior always has the highest index (length of the stack).
999#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Reflect)]
1000pub struct BehaviorIndex(usize);
1001
1002impl BehaviorIndex {
1003    /// Returns the index of the initial behavior. This is always `0`.
1004    pub fn initial() -> Self {
1005        Self(0)
1006    }
1007
1008    /// Returns the index of the behavior before this one, if exists.
1009    pub fn previous(self) -> Option<Self> {
1010        if self == BehaviorIndex::initial() {
1011            return None;
1012        }
1013
1014        Some(Self(self.0.saturating_sub(1)))
1015    }
1016
1017    fn next(self) -> Self {
1018        Self(self.0.saturating_add(1))
1019    }
1020}
1021
1022#[derive(Component, Deref, DerefMut, Reflect)]
1023#[reflect(Component)]
1024struct Memory<T: Behavior> {
1025    stack: Vec<T>,
1026}
1027
1028impl<T: Behavior> Default for Memory<T> {
1029    fn default() -> Self {
1030        Self {
1031            stack: Vec::default(),
1032        }
1033    }
1034}
1035
1036/// A convenient macro for implementation of [`Behavior::filter_next`].
1037///
1038/// # Usage
1039/// For any given pair of states `curr` and `next`, this match expands into a match arm such that:
1040/// ```rust,ignore
1041/// match curr {
1042///     From => matches!(next, To)
1043/// }
1044/// ```
1045/// where `From` is the current possible state, and `To` is the next allowed state.
1046///
1047/// # Example
1048///
1049/// ```rust
1050/// # use bevy::prelude::*;
1051/// # use moonshine_behavior::prelude::*;
1052/// #[derive(Component, Debug)]
1053/// enum Soldier {
1054///     Idle,
1055///     Crouch,
1056///     Fire,
1057///     Sprint,
1058///     Jump,
1059/// }
1060///
1061/// impl Behavior for Soldier {
1062///     fn filter_next(&self, next: &Self) -> bool {
1063///         use Soldier::*;
1064///         match_next! {
1065///             self => next,
1066///             Idle => Crouch | Sprint | Fire | Jump,
1067///             Crouch => Sprint | Fire,
1068///             Sprint => Jump,
1069///         }
1070///     }
1071/// }
1072///
1073/// # assert!(Soldier::Idle.filter_next(&Soldier::Crouch));
1074/// # assert!(!Soldier::Sprint.filter_next(&Soldier::Fire));
1075/// ```
1076#[macro_export]
1077macro_rules! match_next {
1078    { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
1079        match $curr {
1080            $(
1081                $from => matches!($next, $to),
1082            )*
1083            #[allow(unreachable_patterns)]
1084            _ => false,
1085        }
1086    };
1087}