limboai/bt/bt_state.cpp

136 lines
4.9 KiB
C++
Raw Normal View History

/**
* bt_state.cpp
* =============================================================================
* Copyright 2021-2024 Serhii Snitsaruk
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
2022-10-19 18:54:21 +00:00
#include "bt_state.h"
2023-07-20 16:35:36 +00:00
2024-01-07 04:54:17 +00:00
#include "../editor/debugger/limbo_debugger.h"
2024-01-09 12:34:24 +00:00
#include "../util/limbo_compat.h"
2024-01-07 04:54:17 +00:00
#include "../util/limbo_string_names.h"
2023-07-20 16:35:36 +00:00
2024-01-07 04:54:17 +00:00
#ifdef LIMBOAI_MODULE
#include "core/debugger/engine_debugger.h"
2024-01-07 04:54:17 +00:00
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine_debugger.hpp>
#endif // LIMBOAI_GDEXTENSION
2022-10-19 18:54:21 +00:00
void BTState::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
2024-01-23 14:31:56 +00:00
}
if (p_tree.is_valid()) {
p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
2024-01-23 14:31:56 +00:00
}
behavior_tree = p_tree;
_update_blackboard_plan();
} else {
behavior_tree = p_tree;
2024-01-23 14:31:56 +00:00
}
}
void BTState::_update_blackboard_plan() {
if (get_blackboard_plan().is_null()) {
set_blackboard_plan(memnew(BlackboardPlan));
} else if (!RESOURCE_IS_BUILT_IN(get_blackboard_plan())) {
WARN_PRINT_ED("BTState: Using external resource for derived blackboard plan is not supported. Converted to built-in resource.");
set_blackboard_plan(get_blackboard_plan()->duplicate());
} else {
get_blackboard_plan()->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
}
2024-01-23 14:31:56 +00:00
}
2022-10-19 18:54:21 +00:00
void BTState::_setup() {
LimboState::_setup();
2022-12-16 14:29:36 +00:00
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
// TODO: BBNode relies on agent to be scene owner, so if the user provides anything else, the behavior tree can break.
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), get_owner());
#ifdef DEBUG_ENABLED
2024-01-07 04:54:17 +00:00
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
}
#endif
2022-10-19 18:54:21 +00:00
}
void BTState::_exit() {
if (tree_instance.is_valid()) {
tree_instance->abort();
} else {
ERR_PRINT_ONCE("BTState: BehaviorTree is not assigned.");
}
LimboState::_exit();
2022-10-19 18:54:21 +00:00
}
void BTState::_update(double p_delta) {
VCALL_ARGS(_update, p_delta);
if (!active) {
// Bail out if a transition happened in the meantime.
return;
}
ERR_FAIL_NULL(tree_instance);
2022-12-16 14:29:36 +00:00
int status = tree_instance->execute(p_delta);
2022-10-19 18:54:21 +00:00
if (status == BTTask::SUCCESS) {
2022-11-04 12:26:49 +00:00
get_root()->dispatch(success_event, Variant());
2022-10-19 18:54:21 +00:00
} else if (status == BTTask::FAILURE) {
2022-11-04 12:26:49 +00:00
get_root()->dispatch(failure_event, Variant());
2022-10-19 18:54:21 +00:00
}
emit_signal(LW_NAME(updated), p_delta);
2022-10-19 18:54:21 +00:00
}
void BTState::_notification(int p_notification) {
switch (p_notification) {
#ifdef DEBUG_ENABLED
case NOTIFICATION_ENTER_TREE: {
2024-01-07 04:54:17 +00:00
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
}
} break;
#endif // DEBUG_ENABLED
case NOTIFICATION_EXIT_TREE: {
#ifdef DEBUG_ENABLED
2024-01-07 04:54:17 +00:00
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
2023-04-15 08:53:57 +00:00
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
}
#endif // DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
behavior_tree->disconnect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan));
}
}
} break;
}
}
2022-10-19 18:54:21 +00:00
void BTState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTState::set_behavior_tree);
2022-10-19 18:54:21 +00:00
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTState::get_behavior_tree);
ClassDB::bind_method(D_METHOD("get_tree_instance"), &BTState::get_tree_instance);
ClassDB::bind_method(D_METHOD("set_success_event", "event"), &BTState::set_success_event);
2022-11-04 12:26:49 +00:00
ClassDB::bind_method(D_METHOD("get_success_event"), &BTState::get_success_event);
ClassDB::bind_method(D_METHOD("set_failure_event", "event"), &BTState::set_failure_event);
2022-11-04 12:26:49 +00:00
ClassDB::bind_method(D_METHOD("get_failure_event"), &BTState::get_failure_event);
2022-10-19 18:54:21 +00:00
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "success_event"), "set_success_event", "get_success_event");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "failure_event"), "set_failure_event", "get_failure_event");
}
BTState::BTState() {
success_event = LW_NAME(EVENT_SUCCESS);
failure_event = LW_NAME(EVENT_FAILURE);
2022-10-19 18:54:21 +00:00
}