use crate::prelude::*;
use bevy::prelude::*;
use ego_tree::NodeId;
pub(crate) fn plugin(app: &mut App) {
app.add_observer(on_behave_status_report);
}
#[derive(Component)]
pub(crate) struct BehaveDespawnTaskEntity;
#[derive(Component, Debug, Copy, Clone)]
pub struct BehaveCtx {
bt_entity: Entity,
task_entity: Option<Entity>,
task_node: NodeId,
target_entity: Entity,
sup_entity: Option<Entity>,
ctx_type: CtxType,
elapsed_secs: f32,
}
impl std::fmt::Display for BehaveCtx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"BehaveCtx(bt: {}, target: {}, type: {:?})",
self.bt_entity, self.target_entity, self.ctx_type
)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum CtxType {
Trigger,
Entity,
}
impl BehaveCtx {
pub(crate) fn new_for_trigger(task_node: NodeId, tick_ctx: &TickCtx) -> Self {
Self::new(task_node, tick_ctx, CtxType::Trigger, None)
}
pub(crate) fn new_for_entity(
task_node: NodeId,
tick_ctx: &TickCtx,
task_entity: Entity,
) -> Self {
Self::new(task_node, tick_ctx, CtxType::Entity, Some(task_entity))
}
fn new(
task_node: NodeId,
tick_ctx: &TickCtx,
ctx_type: CtxType,
task_entity: Option<Entity>,
) -> Self {
Self {
task_node,
task_entity,
bt_entity: tick_ctx.bt_entity,
target_entity: tick_ctx.target_entity,
sup_entity: tick_ctx.supervisor_entity,
elapsed_secs: tick_ctx.elapsed_secs,
ctx_type,
}
}
pub fn elapsed_secs(&self) -> f32 {
self.elapsed_secs
}
pub fn is_for_trigger(&self) -> bool {
self.ctx_type == CtxType::Trigger
}
pub fn is_for_entity(&self) -> bool {
self.ctx_type == CtxType::Entity
}
pub fn success(&self) -> BehaveStatusReport {
BehaveStatusReport::Success(*self)
}
pub fn failure(&self) -> BehaveStatusReport {
BehaveStatusReport::Failure(*self)
}
pub fn target_entity(&self) -> Entity {
self.target_entity
}
pub fn behave_entity(&self) -> Entity {
self.bt_entity
}
pub fn task_entity(&self) -> Option<Entity> {
self.task_entity
}
pub fn supervisor_entity(&self) -> Option<Entity> {
self.sup_entity
}
pub(crate) fn task_node(&self) -> NodeId {
self.task_node
}
}
#[derive(Debug, Event)]
pub enum BehaveStatusReport {
Success(BehaveCtx),
Failure(BehaveCtx),
}
impl BehaveStatusReport {
pub fn ctx(&self) -> &BehaveCtx {
match self {
BehaveStatusReport::Success(ctx) => ctx,
BehaveStatusReport::Failure(ctx) => ctx,
}
}
}
fn on_behave_status_report(
trigger: On<BehaveStatusReport>,
mut commands: Commands,
mut q_bt: Query<&mut BehaveTree, Without<BehaveFinished>>,
) {
let ctx = trigger.event().ctx();
let Ok(mut bt) = q_bt.get_mut(ctx.behave_entity()) else {
debug!("Failed to get bt entity during status report {:?}", trigger);
return;
};
commands
.entity(ctx.bt_entity)
.remove::<BehaveAwaitingTrigger>();
let task_entity = match trigger.event() {
BehaveStatusReport::Success(ctx) => bt.set_node_result(ctx, true),
BehaveStatusReport::Failure(ctx) => bt.set_node_result(ctx, false),
};
if let Some(task_entity) = task_entity {
commands.entity(task_entity).insert(BehaveDespawnTaskEntity);
}
}