1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4pub mod prelude {
6 pub use crate::{Behavior, BehaviorIndex, BehaviorMut, BehaviorRef};
7 pub use moonshine_kind::{Instance, InstanceCommands};
8
9 pub use crate::transition::{
10 transition, Interrupt, Interruption, Next, Previous, Transition, TransitionSequence,
11 };
12
13 pub use crate::events::{OnActivate, OnPause, OnResume, OnStart, OnStop};
14 pub use crate::plugin::BehaviorPlugin;
15
16 pub use crate::match_next;
17}
18
19pub mod events;
20pub mod transition;
21
22mod plugin;
23
24#[cfg(test)]
25mod tests;
26
27use std::fmt::Debug;
28use std::mem::{replace, swap};
29use std::ops::{Deref, DerefMut, Index, IndexMut};
30
31use bevy_derive::{Deref, DerefMut};
32use bevy_ecs::change_detection::MaybeLocation;
33use bevy_ecs::component::{Components, Mutable, Tick};
34use bevy_ecs::{prelude::*, query::QueryData};
35use bevy_log::prelude::*;
36use bevy_reflect::prelude::*;
37use moonshine_kind::prelude::*;
38
39pub use plugin::BehaviorPlugin;
40
41use crate::events::{OnActivate, OnError, OnPause, OnResume, OnStart, OnStop};
42
43use self::transition::*;
44
45pub trait Behavior: Component<Mutability = Mutable> + Debug + Sized {
52 fn filter_yield(&self, next: &Self) -> bool {
57 match_next! {
58 self => next,
59 _ => _,
60 }
61 }
62
63 fn filter_next(&self, next: &Self) -> bool {
68 match_next! {
69 self => next,
70 _ => _,
71 }
72 }
73
74 fn is_resumable(&self) -> bool {
79 match self {
80 _ => true,
81 }
82 }
83
84 fn on_start(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
86
87 fn on_pause(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
89
90 fn on_resume(&self, _previous: &Self, _commands: InstanceCommands<Self>) {}
92
93 fn on_stop(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
95
96 fn on_activate(&self, _previous: Option<&Self>, _commands: InstanceCommands<Self>) {}
98
99 fn on_suspend(&self, _current: &Self, _commands: InstanceCommands<Self>) {}
101}
102
103#[doc(hidden)]
104trait BehaviorHooks: Behavior {
105 fn invoke_start(&self, previous: Option<&Self>, mut commands: InstanceCommands<Self>) {
106 self.on_start(previous, commands.reborrow());
107 self.on_activate(previous, commands);
108 }
109
110 fn invoke_pause(&self, current: &Self, mut commands: InstanceCommands<Self>) {
111 self.on_suspend(current, commands.reborrow());
112 self.on_pause(current, commands);
113 }
114
115 fn invoke_resume(&self, previous: &Self, mut commands: InstanceCommands<Self>) {
116 self.on_resume(previous, commands.reborrow());
117 self.on_activate(Some(previous), commands);
118 }
119
120 fn invoke_stop(&self, current: &Self, mut commands: InstanceCommands<Self>) {
121 self.on_suspend(current, commands.reborrow());
122 self.on_stop(current, commands);
123 }
124}
125
126impl<T: Behavior> BehaviorHooks for T {}
127
128#[derive(QueryData)]
138pub struct BehaviorRef<T: Behavior> {
139 current: Ref<'static, T>,
140 memory: &'static Memory<T>,
141 transition: &'static Transition<T>,
142 sequence: Has<TransitionSequence<T>>,
143}
144
145impl<T: Behavior> BehaviorRef<T> {
146 pub fn from_entity(entity: EntityRef) -> Option<BehaviorRefItem<T>> {
148 Some(BehaviorRefItem {
149 current: entity.get_ref::<T>()?,
150 memory: entity.get::<Memory<T>>()?,
151 transition: entity.get::<Transition<T>>()?,
152 sequence: entity.contains::<TransitionSequence<T>>(),
153 })
154 }
155}
156
157impl<T: Behavior> BehaviorRefItem<'_, T> {
158 pub fn current(&self) -> &T {
160 &self.current
161 }
162
163 pub fn index(&self) -> BehaviorIndex {
165 BehaviorIndex(self.memory.len())
166 }
167
168 pub fn has_index(&self, index: BehaviorIndex) -> bool {
170 index <= self.index()
171 }
172
173 pub fn previous(&self) -> Option<&T> {
182 self.memory.last()
183 }
184
185 pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
189 self.memory.iter().chain(std::iter::once(self.current()))
190 }
191
192 pub fn has_transition(&self) -> bool {
207 !self.transition.is_none()
208 }
209
210 pub fn has_sequence(&self) -> bool {
214 self.sequence
215 }
216}
217
218impl<T: Behavior> Deref for BehaviorRefItem<'_, T> {
219 type Target = T;
220
221 fn deref(&self) -> &Self::Target {
222 self.current()
223 }
224}
225
226impl<T: Behavior> AsRef<T> for BehaviorRefItem<'_, T> {
227 fn as_ref(&self) -> &T {
228 &self.current
229 }
230}
231
232impl<T: Behavior> DetectChanges for BehaviorRefItem<'_, T> {
233 fn is_added(&self) -> bool {
234 self.current.is_added()
235 }
236
237 fn is_changed(&self) -> bool {
238 self.current.is_changed()
239 }
240
241 fn last_changed(&self) -> Tick {
242 self.current.last_changed()
243 }
244
245 fn added(&self) -> Tick {
246 self.current.added()
247 }
248
249 fn changed_by(&self) -> MaybeLocation {
250 self.current.changed_by()
251 }
252}
253
254impl<T: Behavior> Index<BehaviorIndex> for BehaviorRefItem<'_, T> {
255 type Output = T;
256
257 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
258 if index == self.memory.stack.len() {
259 self.current()
260 } else {
261 &self.memory[index]
262 }
263 }
264}
265
266#[derive(QueryData)]
274#[query_data(mutable)]
275pub struct BehaviorMut<T: Behavior> {
276 current: Mut<'static, T>,
277 memory: &'static mut Memory<T>,
278 transition: &'static mut Transition<T>,
279 sequence: Has<TransitionSequence<T>>,
280}
281
282impl<T: Behavior> BehaviorMutReadOnlyItem<'_, T> {
283 pub fn current(&self) -> &T {
285 &self.current
286 }
287
288 pub fn previous(&self) -> Option<&T> {
290 self.memory.last()
291 }
292
293 pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
295 self.memory.iter().chain(std::iter::once(self.current()))
296 }
297
298 pub fn index(&self) -> BehaviorIndex {
300 BehaviorIndex(self.memory.len())
301 }
302
303 pub fn has_transition(&self) -> bool {
305 !self.transition.is_none()
306 }
307
308 pub fn has_sequence(&self) -> bool {
310 self.sequence
311 }
312}
313
314impl<T: Behavior> Deref for BehaviorMutReadOnlyItem<'_, T> {
315 type Target = T;
316
317 fn deref(&self) -> &Self::Target {
318 self.current()
319 }
320}
321
322impl<T: Behavior> AsRef<T> for BehaviorMutReadOnlyItem<'_, T> {
323 fn as_ref(&self) -> &T {
324 self.current.as_ref()
325 }
326}
327
328impl<T: Behavior> DetectChanges for BehaviorMutReadOnlyItem<'_, T> {
329 fn is_added(&self) -> bool {
330 self.current.is_added()
331 }
332
333 fn is_changed(&self) -> bool {
334 self.current.is_changed()
335 }
336
337 fn last_changed(&self) -> Tick {
338 self.current.last_changed()
339 }
340
341 fn added(&self) -> Tick {
342 self.current.added()
343 }
344
345 fn changed_by(&self) -> MaybeLocation {
346 self.current.changed_by()
347 }
348}
349
350impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutReadOnlyItem<'_, T> {
351 type Output = T;
352
353 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
354 if index == self.memory.stack.len() {
355 self.current()
356 } else {
357 &self.memory[index]
358 }
359 }
360}
361
362impl<T: Behavior> BehaviorMutItem<'_, T> {
363 pub fn current(&self) -> &T {
365 &self.current
366 }
367
368 pub fn current_mut(&mut self) -> &mut T {
370 self.current.as_mut()
371 }
372
373 pub fn previous(&self) -> Option<&T> {
375 self.memory.last()
376 }
377
378 pub fn previous_mut(&mut self) -> Option<&mut T> {
382 self.memory.last_mut()
383 }
384
385 pub fn iter(&self) -> impl Iterator<Item = &T> + '_ {
387 self.memory.iter().chain(std::iter::once(self.current()))
388 }
389
390 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> + '_ {
394 self.memory
395 .iter_mut()
396 .chain(std::iter::once(self.current.as_mut()))
397 }
398
399 pub fn index(&self) -> BehaviorIndex {
401 BehaviorIndex(self.memory.len())
402 }
403
404 pub fn has_index(&self, index: BehaviorIndex) -> bool {
406 index <= self.index()
407 }
408
409 pub fn has_transition(&self) -> bool {
411 !self.transition.is_none()
412 }
413
414 pub fn has_sequence(&self) -> bool {
416 self.sequence
417 }
418
419 #[track_caller]
426 pub fn start(&mut self, next: T) {
427 self.start_with_caller(next, MaybeLocation::caller());
428 }
429
430 #[track_caller]
450 pub fn try_start(&mut self, next: T) -> Result<(), T> {
451 if self.has_transition() || !self.filter_next(&next) {
452 return Err(next);
453 }
454
455 self.start_with_caller(next, MaybeLocation::caller());
456 Ok(())
457 }
458
459 fn start_with_caller(&mut self, next: T, caller: MaybeLocation) {
460 self.set_transition(Next(next), caller);
461 }
462
463 #[track_caller]
475 pub fn interrupt_start(&mut self, next: T) {
476 self.interrupt_start_with_caller(next, MaybeLocation::caller());
477 }
478
479 #[track_caller]
483 pub fn try_interrupt_start(&mut self, next: T) -> Result<(), T> {
484 if self.has_transition() {
485 return Err(next);
486 }
487
488 self.interrupt_start_with_caller(next, MaybeLocation::caller());
489 Ok(())
490 }
491
492 fn interrupt_start_with_caller(&mut self, next: T, caller: MaybeLocation) {
493 self.set_transition(Interrupt(Interruption::Start(next)), caller);
494 }
495
496 #[track_caller]
502 pub fn interrupt_stop(&mut self, index: BehaviorIndex) {
503 self.interrupt_resume_with_caller(index.previous(), MaybeLocation::caller());
504 }
505
506 #[track_caller]
513 pub fn try_interrupt_stop(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
514 if self.has_transition() || !self.has_index(index) || index == BehaviorIndex::initial() {
515 return Err(index);
516 }
517
518 self.interrupt_resume_with_caller(index.previous(), MaybeLocation::caller());
519 Ok(())
520 }
521
522 #[track_caller]
526 pub fn interrupt_resume(&mut self, index: BehaviorIndex) {
527 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
528 }
529
530 #[track_caller]
536 pub fn try_interrupt_resume(&mut self, index: BehaviorIndex) -> Result<(), BehaviorIndex> {
537 if self.has_transition() || !self.has_index(index) {
538 return Err(index);
539 }
540
541 self.interrupt_resume_with_caller(index, MaybeLocation::caller());
542 Ok(())
543 }
544
545 fn interrupt_resume_with_caller(&mut self, index: BehaviorIndex, caller: MaybeLocation) {
546 self.set_transition(Interrupt(Interruption::Resume(index)), caller);
547 }
548
549 #[track_caller]
556 pub fn stop(&mut self) {
557 self.stop_with_caller(MaybeLocation::caller());
558 }
559
560 #[track_caller]
566 pub fn try_stop(&mut self) -> bool {
567 if self.has_transition() || self.memory.is_empty() {
568 return false;
569 }
570
571 self.stop_with_caller(MaybeLocation::caller());
572 true
573 }
574
575 fn stop_with_caller(&mut self, caller: MaybeLocation) {
576 self.set_transition(Previous, caller);
577 }
578
579 #[track_caller]
584 pub fn reset(&mut self) {
585 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
586 }
587
588 #[track_caller]
592 pub fn try_reset(&mut self) -> bool {
593 if self.has_transition() {
594 return false;
595 }
596
597 self.interrupt_resume_with_caller(BehaviorIndex::initial(), MaybeLocation::caller());
598 true
599 }
600
601 fn set_transition(&mut self, transition: Transition<T>, caller: MaybeLocation) {
602 let previous = replace(self.transition.as_mut(), transition);
603 if !previous.is_none() {
604 warn!(
605 "transition override ({caller})): {previous:?} -> {:?}",
606 *self.transition
607 );
608 }
609 }
610
611 fn push(
612 &mut self,
613 instance: Instance<T>,
614 mut next: T,
615 components: &Components,
616 commands: &mut Commands,
617 ) -> bool {
618 let id = components.valid_component_id::<T>().unwrap();
619
620 if self.filter_next(&next) {
621 let previous = {
622 swap(self.current.as_mut(), &mut next);
623 next
624 };
625 self.invoke_start(Some(&previous), commands.instance(instance));
626 let index = self.memory.len();
627 if previous.is_resumable() {
628 let next_index = index + 1;
629 debug!(
630 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{next_index})",
631 *self.current
632 );
633
634 previous.invoke_pause(&self.current, commands.instance(instance));
635
636 commands.trigger_targets(
637 OnPause {
638 index: BehaviorIndex(index),
639 },
640 (*instance, id),
641 );
642 commands.trigger_targets(
643 OnStart {
644 index: BehaviorIndex(next_index),
645 },
646 (*instance, id),
647 );
648 commands.trigger_targets(
649 OnActivate {
650 index: BehaviorIndex(next_index),
651 resume: false,
652 },
653 (*instance, id),
654 );
655
656 self.memory.push(previous);
657 } else {
658 debug!(
659 "{instance:?}: {previous:?} (#{index}) -> {:?} (#{index})",
660 *self.current
661 );
662
663 previous.invoke_stop(&self.current, commands.instance(instance));
664
665 commands.trigger_targets(OnStop { behavior: previous }, (*instance, id));
666 commands.trigger_targets(
667 OnStart {
668 index: BehaviorIndex(index),
669 },
670 (*instance, id),
671 );
672 commands.trigger_targets(
673 OnActivate {
674 index: BehaviorIndex(index),
675 resume: false,
676 },
677 (*instance, id),
678 );
679 }
680 true
681 } else {
682 warn!(
683 "{instance:?}: transition {:?} -> {next:?} is not allowed",
684 *self.current
685 );
686
687 commands.trigger_targets(
688 OnError(TransitionError::RejectedNext(next)),
689 (*instance, id),
690 );
691 false
692 }
693 }
694
695 fn interrupt(
696 &mut self,
697 instance: Instance<T>,
698 next: T,
699 components: &Components,
700 commands: &mut Commands,
701 ) {
702 let id = components.valid_component_id::<T>().unwrap();
703
704 while self.filter_yield(&next) && !self.memory.is_empty() {
705 let index = self.memory.len();
706 if let Some(mut next) = self.memory.pop() {
707 let previous = {
708 swap(self.current.as_mut(), &mut next);
709 next
710 };
711 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
712 previous.invoke_stop(&self.current, commands.instance(instance));
713 commands.trigger_targets(OnStop { behavior: previous }, (*instance, id));
714 }
715 }
716
717 self.push(instance, next, components, commands);
718 }
719
720 fn pop(
721 &mut self,
722 instance: Instance<T>,
723 components: &Components,
724 commands: &mut Commands,
725 ) -> bool {
726 let id = components.valid_component_id::<T>().unwrap();
727 let index = self.memory.len();
728 if let Some(mut next) = self.memory.pop() {
729 let next_index = self.memory.len();
730 debug!(
731 "{instance:?}: {:?} (#{index}) -> {next:?} (#{next_index})",
732 *self.current
733 );
734 let previous = {
735 swap(self.current.as_mut(), &mut next);
736 next
737 };
738 self.invoke_resume(&previous, commands.instance(instance));
739 previous.invoke_stop(&self.current, commands.instance(instance));
740 commands.trigger_targets(
741 OnResume {
742 index: BehaviorIndex(next_index),
743 },
744 (*instance, id),
745 );
746 commands.trigger_targets(
747 OnActivate {
748 index: BehaviorIndex(next_index),
749 resume: true,
750 },
751 (*instance, id),
752 );
753 commands.trigger_targets(OnStop { behavior: previous }, (*instance, id));
754 true
755 } else {
756 warn!(
757 "{instance:?}: transition {:?} -> None is not allowed",
758 *self.current
759 );
760 commands.trigger_targets(OnError::<T>(TransitionError::NoPrevious), (*instance, id));
761 false
762 }
763 }
764
765 fn clear(
766 &mut self,
767 instance: Instance<T>,
768 index: BehaviorIndex,
769 components: &Components,
770 commands: &mut Commands,
771 ) {
772 let id = components.valid_component_id::<T>().unwrap();
773
774 while self.index() > index.next() {
776 let index = self.memory.len();
777 let previous = self.memory.pop().unwrap();
778 let next = self.memory.last().unwrap();
779 debug!("{instance:?}: {:?} (#{index}) -> Interrupt", previous);
780 previous.invoke_stop(next, commands.instance(instance));
781 commands.trigger_targets(OnStop { behavior: previous }, (*instance, id));
782 }
783
784 self.pop(instance, components, commands);
786 }
787}
788
789impl<T: Behavior> Deref for BehaviorMutItem<'_, T> {
790 type Target = T;
791
792 fn deref(&self) -> &Self::Target {
793 self.current()
794 }
795}
796
797impl<T: Behavior> DerefMut for BehaviorMutItem<'_, T> {
798 fn deref_mut(&mut self) -> &mut Self::Target {
799 self.current_mut()
800 }
801}
802
803impl<T: Behavior> DetectChanges for BehaviorMutItem<'_, T> {
804 fn is_added(&self) -> bool {
805 self.current.is_added()
806 }
807
808 fn is_changed(&self) -> bool {
809 self.current.is_changed()
810 }
811
812 fn last_changed(&self) -> Tick {
813 self.current.last_changed()
814 }
815
816 fn added(&self) -> Tick {
817 self.current.added()
818 }
819
820 fn changed_by(&self) -> MaybeLocation {
821 self.current.changed_by()
822 }
823}
824
825impl<T: Behavior> DetectChangesMut for BehaviorMutItem<'_, T> {
826 type Inner = T;
827
828 fn set_changed(&mut self) {
829 self.current.set_changed()
830 }
831
832 fn set_last_changed(&mut self, last_changed: Tick) {
833 self.current.set_last_changed(last_changed)
834 }
835
836 fn bypass_change_detection(&mut self) -> &mut Self::Inner {
837 self.current.bypass_change_detection()
838 }
839
840 fn set_added(&mut self) {
841 self.current.set_added()
842 }
843
844 fn set_last_added(&mut self, last_added: Tick) {
845 self.current.set_last_added(last_added)
846 }
847}
848
849impl<T: Behavior> AsRef<T> for BehaviorMutItem<'_, T> {
850 fn as_ref(&self) -> &T {
851 self.current.as_ref()
852 }
853}
854
855impl<T: Behavior> AsMut<T> for BehaviorMutItem<'_, T> {
856 fn as_mut(&mut self) -> &mut T {
857 self.current.as_mut()
858 }
859}
860
861impl<T: Behavior> Index<BehaviorIndex> for BehaviorMutItem<'_, T> {
862 type Output = T;
863
864 fn index(&self, BehaviorIndex(index): BehaviorIndex) -> &Self::Output {
865 if index == self.memory.stack.len() {
866 self.current()
867 } else {
868 &self.memory[index]
869 }
870 }
871}
872
873impl<T: Behavior> IndexMut<BehaviorIndex> for BehaviorMutItem<'_, T> {
874 fn index_mut(&mut self, BehaviorIndex(index): BehaviorIndex) -> &mut Self::Output {
875 if index == self.memory.stack.len() {
876 self.current_mut()
877 } else {
878 &mut self.memory[index]
879 }
880 }
881}
882
883#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Reflect)]
888pub struct BehaviorIndex(usize);
889
890impl BehaviorIndex {
891 pub fn initial() -> Self {
893 Self(0)
894 }
895
896 fn next(self) -> Self {
897 Self(self.0.saturating_add(1))
898 }
899
900 fn previous(self) -> Self {
901 Self(self.0.saturating_sub(1))
902 }
903}
904
905#[derive(Component, Deref, DerefMut, Reflect)]
906#[reflect(Component)]
907struct Memory<T: Behavior> {
908 stack: Vec<T>,
909}
910
911impl<T: Behavior> Default for Memory<T> {
912 fn default() -> Self {
913 Self {
914 stack: Vec::default(),
915 }
916 }
917}
918
919#[macro_export]
960macro_rules! match_next {
961 { $curr:ident => $next:ident, $($from:pat => $to:pat),* $(,)? } => {
962 match $curr {
963 $(
964 $from => matches!($next, $to),
965 )*
966 #[allow(unreachable_patterns)]
967 _ => false,
968 }
969 };
970}