behaviortree-core 0.1.0

Core implementaion of behaviortree
Documentation
// Copyright © 2025 Stephan Kunz
//! Built-In behaviors of [`behaviortree`](crate).

#![allow(unused, unreachable_code)]

use core::{
	any::{Any, TypeId},
	fmt::Debug,
	str::FromStr,
};

use alloc::{
	borrow::ToOwned,
	boxed::Box,
	string::{String, ToString},
	vec::Vec,
};

use databoard::{Databoard, Error, RemappingList};
use dataport::{
	BoundValueReadGuard, BoundValueWriteGuard, PortCollection, PortCollectionAccessors, PortCollectionAccessorsCommon,
};
use tinyscript::{Environment, ScriptingValue};

use crate::{BehaviorTickCallback, ConstString, behavior_description::BehaviorDescription, behavior_state::BehaviorState};

/// Structure for implementing behaviors.
#[derive(Default)]
pub struct BehaviorData {
	/// UID of the behavior within the [`BehaviorTree`](crate::tree::BehaviorTree).
	/// 65536 behaviors in a [`BehaviorTree`](crate::tree::BehaviorTree) should be sufficient.
	/// The ordering of the uid is following the creation order by the [`XmlParser`](crate::factory::xml_parser::XmlParser).
	/// This should end up in a depth first ordering.
	uid: u16,
	/// Current state of the behavior.
	state: BehaviorState,
	/// Reference to the [`Databoard`] for the element.
	blackboard: Databoard,
	/// Description of the Behavior.
	description: Box<BehaviorDescription>,
	/// List of pre state change callbacks with an identifier.
	/// These callbacks can be used for observation of the [`BehaviorTreeElement`] and
	/// for manipulation of the resulting [`BehaviorState`] of a tick.
	pre_state_change_hooks: Vec<(ConstString, Box<BehaviorTickCallback>)>,
}

impl BehaviorData {
	/// Constructor
	#[must_use]
	pub fn create(uid: u16, blackboard: Databoard, description: BehaviorDescription) -> Self {
		Self {
			uid,
			state: BehaviorState::default(),
			blackboard,
			description: Box::new(description),
			pre_state_change_hooks: Vec::default(),
		}
	}

	/// returns a reference to the blackboard.
	#[must_use]
	pub const fn blackboard(&self) -> &Databoard {
		&self.blackboard
	}

	/// returns a mutable reference to the blackboard.
	#[must_use]
	pub const fn blackboard_mut(&mut self) -> &mut Databoard {
		&mut self.blackboard
	}

	/// Returns a reference to the desription.
	#[must_use]
	pub const fn description(&self) -> &BehaviorDescription {
		&self.description
	}

	/// Returns a mutable reference to the desription.
	#[must_use]
	pub const fn description_mut(&mut self) -> &mut BehaviorDescription {
		&mut self.description
	}

	/// Returns whether a behavior is active.
	#[must_use]
	pub fn is_active(&self) -> bool {
		self.state != BehaviorState::Idle && self.state != BehaviorState::Skipped
	}

	/// Returns the name.
	#[must_use]
	pub const fn name(&self) -> &ConstString {
		self.description.name()
	}

	/// Returns the uid.
	#[must_use]
	pub const fn uid(&self) -> u16 {
		self.uid
	}

	/// Method to get the state.
	#[must_use]
	pub const fn state(&self) -> BehaviorState {
		self.state
	}

	/// Method to set the state.
	pub fn set_state(&mut self, state: BehaviorState) {
		if state != self.state {
			// Callback before setting state
			let mut state = state;
			for (_, callback) in &self.pre_state_change_hooks {
				callback(self, &mut state);
			}
			self.state = state;
		}
	}

	/// Add a pre state change callback with the given name.
	/// The name is not unique, which is important when removing callback.
	pub fn add_pre_state_change_callback<T>(&mut self, name: ConstString, callback: T)
	where
		T: Fn(&Self, &mut BehaviorState) + Send + Sync + 'static,
	{
		self.pre_state_change_hooks
			.push((name, Box::new(callback)));
	}

	/// Remove any pre state change callback with the given name.
	pub fn remove_pre_state_change_callback(&mut self, name: &str) {
		self.pre_state_change_hooks
			.retain(|(cb_name, _)| cb_name.as_ref() != name);
	}

	/// Returns a reference to the full path
	#[must_use]
	pub const fn full_path(&self) -> &ConstString {
		self.description.groot2_path()
	}
}