1use std::sync::Arc;
4
5use bevy::prelude::*;
6#[cfg(feature = "trace")]
7use bevy::utils::tracing::trace;
8
9use crate::thinker::{Action, ActionSpan, Actor};
10
11#[derive(Debug, Clone, Component, Eq, PartialEq, Reflect)]
19#[component(storage = "SparseSet")]
20pub enum ActionState {
21 Init,
23
24 Requested,
27
28 Executing,
32
33 Cancelled,
40
41 Success,
44
45 Failure,
48}
49
50impl Default for ActionState {
51 fn default() -> Self {
52 Self::Init
53 }
54}
55
56impl ActionState {
57 pub fn new() -> Self {
58 Self::default()
59 }
60}
61
62#[derive(Debug, Clone, Eq, PartialEq)]
63pub(crate) struct ActionBuilderId;
64
65#[derive(Debug, Clone)]
66pub(crate) struct ActionBuilderWrapper(pub Arc<ActionBuilderId>, pub Arc<dyn ActionBuilder>);
67
68impl ActionBuilderWrapper {
69 pub fn new(builder: Arc<dyn ActionBuilder>) -> Self {
70 ActionBuilderWrapper(Arc::new(ActionBuilderId), builder)
71 }
72}
73
74#[reflect_trait]
82pub trait ActionBuilder: std::fmt::Debug + Send + Sync {
83 fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity);
121
122 fn label(&self) -> Option<&str> {
126 None
127 }
128}
129
130pub fn spawn_action<T: ActionBuilder + ?Sized>(
133 builder: &T,
134 cmd: &mut Commands,
135 actor: Entity,
136) -> Entity {
137 let action_ent = Action(cmd.spawn_empty().id());
138 let span = ActionSpan::new(action_ent.entity(), ActionBuilder::label(builder));
139 let _guard = span.span().enter();
140 debug!("New Action spawned.");
141 cmd.entity(action_ent.entity())
142 .insert(Name::new("Action"))
143 .insert(ActionState::new())
144 .insert(Actor(actor));
145 builder.build(cmd, action_ent.entity(), actor);
146 std::mem::drop(_guard);
147 cmd.entity(action_ent.entity()).insert(span);
148 action_ent.entity()
149}
150
151#[derive(Debug, Reflect)]
154#[reflect(ActionBuilder)]
155pub struct StepsBuilder {
156 label: Option<String>,
157 steps_labels: Vec<String>,
158 #[reflect(ignore)]
159 steps: Vec<Arc<dyn ActionBuilder>>,
160}
161
162impl StepsBuilder {
163 pub fn label<S: Into<String>>(mut self, label: S) -> Self {
165 self.label = Some(label.into());
166 self
167 }
168
169 pub fn step(mut self, action_builder: impl ActionBuilder + 'static) -> Self {
171 if let Some(label) = action_builder.label() {
172 self.steps_labels.push(label.into());
173 } else {
174 self.steps_labels.push("Unlabeled Action".into());
175 }
176 self.steps.push(Arc::new(action_builder));
177 self
178 }
179}
180
181impl ActionBuilder for StepsBuilder {
182 fn label(&self) -> Option<&str> {
183 self.label.as_deref()
184 }
185
186 fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity) {
187 if let Some(step) = self.steps.first() {
188 let child_action = spawn_action(step.as_ref(), cmd, actor);
189 cmd.entity(action)
190 .insert(Name::new("Steps Action"))
191 .insert(Steps {
192 active_step: 0,
193 active_ent: Action(child_action),
194 steps: self.steps.clone(),
195 steps_labels: self.steps_labels.clone(),
196 })
197 .add_children(&[child_action]);
198 }
199 }
200}
201
202#[derive(Component, Debug, Reflect)]
228pub struct Steps {
229 #[reflect(ignore)]
230 steps: Vec<Arc<dyn ActionBuilder>>,
231 steps_labels: Vec<String>,
232 active_step: usize,
233 active_ent: Action,
234}
235
236impl Steps {
237 pub fn build() -> StepsBuilder {
239 StepsBuilder {
240 steps: Vec::new(),
241 steps_labels: Vec::new(),
242 label: None,
243 }
244 }
245}
246
247pub fn steps_system(
249 mut cmd: Commands,
250 mut steps_q: Query<(Entity, &Actor, &mut Steps, &ActionSpan)>,
251 mut states: Query<&mut ActionState>,
252) {
253 use ActionState::*;
254 for (seq_ent, Actor(actor), mut steps_action, _span) in steps_q.iter_mut() {
255 let active_ent = steps_action.active_ent.entity();
256 let current_state = states.get_mut(seq_ent).unwrap().clone();
257 #[cfg(feature = "trace")]
258 let _guard = _span.span().enter();
259 match current_state {
260 Requested => {
261 #[cfg(feature = "trace")]
263 trace!(
264 "Initializing StepsAction and requesting first step: {:?}",
265 active_ent
266 );
267 *states.get_mut(active_ent).unwrap() = Requested;
268 *states.get_mut(seq_ent).unwrap() = Executing;
269 }
270 Executing => {
271 let mut step_state = states.get_mut(active_ent).unwrap();
272 match *step_state {
273 Init => {
274 *step_state = Requested;
276 }
277 Executing | Requested => {
278 }
280 Cancelled => {
281 }
283 Failure => {
284 #[cfg(feature = "trace")]
286 trace!("Step {:?} failed. Failing entire StepsAction.", active_ent);
287 let step_state = step_state.clone();
288 let mut seq_state = states.get_mut(seq_ent).expect("idk");
289 *seq_state = step_state;
290 if let Some(ent) = cmd.get_entity(steps_action.active_ent.entity()) {
291 ent.despawn_recursive();
292 }
293 }
294 Success if steps_action.active_step == steps_action.steps.len() - 1 => {
295 #[cfg(feature = "trace")]
297 trace!("StepsAction completed all steps successfully.");
298 let step_state = step_state.clone();
299 let mut seq_state = states.get_mut(seq_ent).expect("idk");
300 *seq_state = step_state;
301 if let Some(ent) = cmd.get_entity(steps_action.active_ent.entity()) {
302 ent.despawn_recursive();
303 }
304 }
305 Success => {
306 #[cfg(feature = "trace")]
307 trace!("Step succeeded, but there's more steps. Spawning next action.");
308 if let Some(ent) = cmd.get_entity(steps_action.active_ent.entity()) {
310 ent.despawn_recursive();
311 }
312
313 steps_action.active_step += 1;
314 let step_builder = steps_action.steps[steps_action.active_step].clone();
315 let step_ent = spawn_action(step_builder.as_ref(), &mut cmd, *actor);
316 #[cfg(feature = "trace")]
317 trace!("Spawned next step: {:?}", step_ent);
318 cmd.entity(seq_ent).add_children(&[step_ent]);
319 steps_action.active_ent = Action(step_ent);
320 }
321 }
322 }
323 Cancelled => {
324 #[cfg(feature = "trace")]
326 trace!("StepsAction has been cancelled. Cancelling current step {:?} before finalizing.", active_ent);
327 let mut step_state = states.get_mut(active_ent).expect("oops");
328 if *step_state == Requested || *step_state == Executing || *step_state == Init {
329 *step_state = Cancelled;
330 } else if *step_state == Failure || *step_state == Success {
331 *states.get_mut(seq_ent).unwrap() = step_state.clone();
332 }
333 }
334 Init | Success | Failure => {
335 }
337 }
338 }
339}
340
341#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Reflect)]
343pub enum ConcurrentMode {
344 Race,
346 Join,
348}
349
350#[derive(Debug, Reflect)]
353pub struct ConcurrentlyBuilder {
354 mode: ConcurrentMode,
355 #[reflect(ignore)]
356 actions: Vec<Arc<dyn ActionBuilder>>,
357 action_labels: Vec<String>,
358 label: Option<String>,
359}
360
361impl ConcurrentlyBuilder {
362 pub fn label<S: Into<String>>(mut self, label: S) -> Self {
364 self.label = Some(label.into());
365 self
366 }
367
368 pub fn push(mut self, action_builder: impl ActionBuilder + 'static) -> Self {
370 if let Some(label) = action_builder.label() {
371 self.action_labels.push(label.into());
372 } else {
373 self.action_labels.push("Unnamed Action".into());
374 }
375 self.actions.push(Arc::new(action_builder));
376 self
377 }
378
379 pub fn mode(mut self, mode: ConcurrentMode) -> Self {
381 self.mode = mode;
382 self
383 }
384}
385
386impl ActionBuilder for ConcurrentlyBuilder {
387 fn label(&self) -> Option<&str> {
388 self.label.as_deref()
389 }
390
391 fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity) {
392 let children: Vec<Entity> = self
393 .actions
394 .iter()
395 .map(|action| spawn_action(action.as_ref(), cmd, actor))
396 .collect();
397 cmd.entity(action)
398 .insert(Name::new("Concurrent Action"))
399 .add_children(&children[..])
400 .insert(Concurrently {
401 actions: children.into_iter().map(Action).collect(),
402 action_labels: self.action_labels.clone(),
403 mode: self.mode,
404 });
405 }
406}
407
408#[derive(Component, Debug, Reflect)]
439pub struct Concurrently {
440 mode: ConcurrentMode,
441 actions: Vec<Action>,
442 action_labels: Vec<String>,
443}
444
445impl Concurrently {
446 pub fn build() -> ConcurrentlyBuilder {
448 ConcurrentlyBuilder {
449 actions: Vec::new(),
450 action_labels: Vec::new(),
451 mode: ConcurrentMode::Join,
452 label: None,
453 }
454 }
455}
456
457pub fn concurrent_system(
459 concurrent_q: Query<(Entity, &Concurrently, &ActionSpan)>,
460 mut states_q: Query<&mut ActionState>,
461) {
462 use ActionState::*;
463 for (seq_ent, concurrent_action, _span) in concurrent_q.iter() {
464 let current_state = states_q.get_mut(seq_ent).expect("uh oh").clone();
465 #[cfg(feature = "trace")]
466 let _guard = _span.span.enter();
467 match current_state {
468 Requested => {
469 #[cfg(feature = "trace")]
470 trace!(
471 "Initializing Concurrently action with {} children.",
472 concurrent_action.actions.len()
473 );
474 let mut current_state = states_q.get_mut(seq_ent).expect("uh oh");
476 *current_state = Executing;
477 for action in concurrent_action.actions.iter() {
478 let child_ent = action.entity();
479 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
480 *child_state = Requested;
481 }
482 }
483 Executing => match concurrent_action.mode {
484 ConcurrentMode::Join => {
485 let mut all_success = true;
486 let mut failed_idx = None;
487 for (idx, action) in concurrent_action.actions.iter().enumerate() {
488 let child_ent = action.entity();
489 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
490 match *child_state {
491 Failure => {
492 failed_idx = Some(idx);
493 all_success = false;
494 #[cfg(feature = "trace")]
495 trace!("Join action has failed. Cancelling all other actions that haven't completed yet.");
496 }
497 Success => {}
498 _ => {
499 all_success = false;
500 if failed_idx.is_some() {
501 *child_state = Cancelled;
502 }
503 }
504 }
505 }
506 if all_success {
507 let mut state_var = states_q.get_mut(seq_ent).expect("uh oh");
508 *state_var = Success;
509 } else if let Some(idx) = failed_idx {
510 for action in concurrent_action.actions.iter().take(idx) {
511 let child_ent = action.entity();
512 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
513 match *child_state {
514 Failure | Success => {}
515 _ => {
516 *child_state = Cancelled;
517 }
518 }
519 }
520 let mut state_var = states_q.get_mut(seq_ent).expect("uh oh");
521 *state_var = Failure;
522 }
523 }
524 ConcurrentMode::Race => {
525 let mut all_failure = true;
526 let mut succeed_idx = None;
527 for (idx, action) in concurrent_action.actions.iter().enumerate() {
528 let child_ent = action.entity();
529 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
530 match *child_state {
531 Failure => {}
532 Success => {
533 succeed_idx = Some(idx);
534 all_failure = false;
535 #[cfg(feature = "trace")]
536 trace!("Race action has succeeded. Cancelling all other actions that haven't completed yet.");
537 }
538 _ => {
539 all_failure = false;
540 if succeed_idx.is_some() {
541 *child_state = Cancelled;
542 }
543 }
544 }
545 }
546 if all_failure {
547 let mut state_var = states_q.get_mut(seq_ent).expect("uh oh");
548 *state_var = Failure;
549 } else if let Some(idx) = succeed_idx {
550 for action in concurrent_action.actions.iter().take(idx) {
551 let child_ent = action.entity();
552 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
553 match *child_state {
554 Failure | Success => {}
555 _ => {
556 *child_state = Cancelled;
557 }
558 }
559 }
560 let mut state_var = states_q.get_mut(seq_ent).expect("uh oh");
561 *state_var = Success;
562 }
563 }
564 },
565 Cancelled => {
566 let mut all_done = true;
568 let mut any_failed = false;
569 let mut any_success = false;
570 for action in concurrent_action.actions.iter() {
571 let child_ent = action.entity();
572 let mut child_state = states_q.get_mut(child_ent).expect("uh oh");
573 match *child_state {
574 Init => {}
575 Success => {
576 any_success = true;
577 }
578 Failure => {
579 any_failed = true;
580 }
581 _ => {
582 all_done = false;
583 *child_state = Cancelled;
584 }
585 }
586 }
587 if all_done {
588 let mut state_var = states_q.get_mut(seq_ent).expect("uh oh");
589 match concurrent_action.mode {
590 ConcurrentMode::Race => {
591 if any_success {
592 #[cfg(feature = "trace")]
593 trace!("Race action has succeeded due to succeeded children.");
594 *state_var = Success;
595 } else {
596 #[cfg(feature = "trace")]
597 trace!("No race children has completed Successfully.");
598 *state_var = Failure;
599 }
600 }
601 ConcurrentMode::Join => {
602 if any_failed {
603 #[cfg(feature = "trace")]
604 trace!("Join action has failed due to failed children.");
605 *state_var = Failure;
606 } else {
607 #[cfg(feature = "trace")]
608 trace!("All Join children have completed Successfully.");
609 *state_var = Success;
610 }
611 }
612 }
613 }
614 }
615 Init | Success | Failure => {
616 }
618 }
619 }
620}