Skip to main content

behaviortree_core/
behavior_data.rs

1// Copyright © 2025 Stephan Kunz
2//! Built-In behaviors of [`behaviortree`](crate).
3
4#![allow(unused, unreachable_code)]
5
6use core::{
7	any::{Any, TypeId},
8	fmt::Debug,
9	str::FromStr,
10};
11
12use alloc::{
13	borrow::ToOwned,
14	boxed::Box,
15	string::{String, ToString},
16	vec::Vec,
17};
18
19use databoard::{Databoard, Error, RemappingList};
20use dataport::{
21	BoundValueReadGuard, BoundValueWriteGuard, PortCollection, PortCollectionAccessors, PortCollectionAccessorsCommon,
22};
23use tinyscript::{Environment, ScriptingValue};
24
25use crate::{BehaviorTickCallback, ConstString, behavior_description::BehaviorDescription, behavior_state::BehaviorState};
26
27/// Structure for implementing behaviors.
28#[derive(Default)]
29pub struct BehaviorData {
30	/// UID of the behavior within the [`BehaviorTree`](crate::tree::BehaviorTree).
31	/// 65536 behaviors in a [`BehaviorTree`](crate::tree::BehaviorTree) should be sufficient.
32	/// The ordering of the uid is following the creation order by the [`XmlParser`](crate::factory::xml_parser::XmlParser).
33	/// This should end up in a depth first ordering.
34	uid: u16,
35	/// Current state of the behavior.
36	state: BehaviorState,
37	/// Reference to the [`Databoard`] for the element.
38	blackboard: Databoard,
39	/// Description of the Behavior.
40	description: Box<BehaviorDescription>,
41	/// List of pre state change callbacks with an identifier.
42	/// These callbacks can be used for observation of the [`BehaviorTreeElement`] and
43	/// for manipulation of the resulting [`BehaviorState`] of a tick.
44	pre_state_change_hooks: Vec<(ConstString, Box<BehaviorTickCallback>)>,
45}
46
47impl BehaviorData {
48	/// Constructor
49	#[must_use]
50	pub fn create(uid: u16, blackboard: Databoard, description: BehaviorDescription) -> Self {
51		Self {
52			uid,
53			state: BehaviorState::default(),
54			blackboard,
55			description: Box::new(description),
56			pre_state_change_hooks: Vec::default(),
57		}
58	}
59
60	/// returns a reference to the blackboard.
61	#[must_use]
62	pub const fn blackboard(&self) -> &Databoard {
63		&self.blackboard
64	}
65
66	/// returns a mutable reference to the blackboard.
67	#[must_use]
68	pub const fn blackboard_mut(&mut self) -> &mut Databoard {
69		&mut self.blackboard
70	}
71
72	/// Returns a reference to the desription.
73	#[must_use]
74	pub const fn description(&self) -> &BehaviorDescription {
75		&self.description
76	}
77
78	/// Returns a mutable reference to the desription.
79	#[must_use]
80	pub const fn description_mut(&mut self) -> &mut BehaviorDescription {
81		&mut self.description
82	}
83
84	/// Returns whether a behavior is active.
85	#[must_use]
86	pub fn is_active(&self) -> bool {
87		self.state != BehaviorState::Idle && self.state != BehaviorState::Skipped
88	}
89
90	/// Returns the name.
91	#[must_use]
92	pub const fn name(&self) -> &ConstString {
93		self.description.name()
94	}
95
96	/// Returns the uid.
97	#[must_use]
98	pub const fn uid(&self) -> u16 {
99		self.uid
100	}
101
102	/// Method to get the state.
103	#[must_use]
104	pub const fn state(&self) -> BehaviorState {
105		self.state
106	}
107
108	/// Method to set the state.
109	pub fn set_state(&mut self, state: BehaviorState) {
110		if state != self.state {
111			// Callback before setting state
112			let mut state = state;
113			for (_, callback) in &self.pre_state_change_hooks {
114				callback(self, &mut state);
115			}
116			self.state = state;
117		}
118	}
119
120	/// Add a pre state change callback with the given name.
121	/// The name is not unique, which is important when removing callback.
122	pub fn add_pre_state_change_callback<T>(&mut self, name: ConstString, callback: T)
123	where
124		T: Fn(&Self, &mut BehaviorState) + Send + Sync + 'static,
125	{
126		self.pre_state_change_hooks
127			.push((name, Box::new(callback)));
128	}
129
130	/// Remove any pre state change callback with the given name.
131	pub fn remove_pre_state_change_callback(&mut self, name: &str) {
132		self.pre_state_change_hooks
133			.retain(|(cb_name, _)| cb_name.as_ref() != name);
134	}
135
136	/// Returns a reference to the full path
137	#[must_use]
138	pub const fn full_path(&self) -> &ConstString {
139		self.description.groot2_path()
140	}
141}