/** * limbo_debugger.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. * ============================================================================= */ #include "limbo_debugger.h" #include "../../bt/bt_instance.h" #include "../../bt/tasks/bt_task.h" #include "../../util/limbo_compat.h" #include "behavior_tree_data.h" #ifdef LIMBOAI_MODULE #include "core/debugger/engine_debugger.h" #include "core/io/resource.h" #include "core/string/node_path.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #endif // LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION #include #include #include #endif // LIMBOAI_GDEXTENSION //**** LimboDebugger LimboDebugger *LimboDebugger::singleton = nullptr; LimboDebugger::LimboDebugger() { singleton = this; #if defined(DEBUG_ENABLED) && defined(LIMBOAI_MODULE) EngineDebugger::register_message_capture("limboai", EngineDebugger::Capture(nullptr, LimboDebugger::parse_message)); #elif defined(DEBUG_ENABLED) && defined(LIMBOAI_GDEXTENSION) EngineDebugger::get_singleton()->register_message_capture("limboai", callable_mp(this, &LimboDebugger::parse_message_gdext)); #endif } LimboDebugger::~LimboDebugger() { singleton = nullptr; } void LimboDebugger::initialize() { if (IS_DEBUGGER_ACTIVE()) { memnew(LimboDebugger); } } void LimboDebugger::deinitialize() { if (singleton) { memdelete(singleton); } } void LimboDebugger::_bind_methods() { } #ifdef DEBUG_ENABLED Error LimboDebugger::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) { r_captured = true; if (p_msg == "track_bt_player") { singleton->_track_tree(p_args[0]); } else if (p_msg == "untrack_bt_player") { singleton->_untrack_tree(); } else if (p_msg == "start_session") { singleton->session_active = true; singleton->_send_active_bt_players(); } else if (p_msg == "stop_session") { singleton->session_active = false; } else { r_captured = false; } return OK; } #ifdef LIMBOAI_GDEXTENSION bool LimboDebugger::parse_message_gdext(const String &p_msg, const Array &p_args) { bool r_captured; LimboDebugger::parse_message(nullptr, p_msg, p_args, r_captured); return r_captured; } #endif // LIMBOAI_GDEXTENSION void LimboDebugger::register_bt_instance(uint64_t p_instance_id) { ERR_FAIL_COND(p_instance_id == 0); if (!IS_DEBUGGER_ACTIVE()) { return; } BTInstance *inst = Object::cast_to(OBJECT_DB_GET_INSTANCE(p_instance_id)); ERR_FAIL_NULL(inst); ERR_FAIL_COND(!inst->is_instance_valid()); if (active_bt_instances.has(p_instance_id)) { return; } if (!inst->is_connected(LW_NAME(freed), callable_mp(this, &LimboDebugger::unregister_bt_instance).bind(p_instance_id))) { inst->connect(LW_NAME(freed), callable_mp(this, &LimboDebugger::unregister_bt_instance).bind(p_instance_id)); } active_bt_instances.insert(p_instance_id); if (session_active) { _send_active_bt_players(); } } void LimboDebugger::unregister_bt_instance(uint64_t p_instance_id) { if (!active_bt_instances.has(p_instance_id)) { return; } if (tracked_instance_id == p_instance_id) { _untrack_tree(); } active_bt_instances.erase(p_instance_id); if (session_active) { _send_active_bt_players(); } } bool LimboDebugger::is_active() const { return IS_DEBUGGER_ACTIVE(); } void LimboDebugger::_track_tree(uint64_t p_instance_id) { ERR_FAIL_COND(!active_bt_instances.has(p_instance_id)); _untrack_tree(); tracked_instance_id = p_instance_id; BTInstance *inst = Object::cast_to(OBJECT_DB_GET_INSTANCE(p_instance_id)); ERR_FAIL_NULL(inst); inst->connect(LW_NAME(updated), callable_mp(this, &LimboDebugger::_on_bt_instance_updated).bind(p_instance_id)); } void LimboDebugger::_untrack_tree() { if (tracked_instance_id == 0) { return; } BTInstance *inst = Object::cast_to(OBJECT_DB_GET_INSTANCE(tracked_instance_id)); if (inst) { inst->disconnect(LW_NAME(updated), callable_mp(this, &LimboDebugger::_on_bt_instance_updated)); } tracked_instance_id = 0; } void LimboDebugger::_send_active_bt_players() { Array arr; for (uint64_t instance_id : active_bt_instances) { arr.append(instance_id); BTInstance *inst = Object::cast_to(OBJECT_DB_GET_INSTANCE(instance_id)); if (inst == nullptr) { ERR_PRINT("LimboDebugger::_send_active_bt_players: Registered BTInstance not found (no longer exists?)."); continue; } Node *owner_node = inst->get_owner_node(); arr.append(owner_node ? owner_node->get_path() : NodePath()); } EngineDebugger::get_singleton()->send_message("limboai:active_bt_players", arr); } void LimboDebugger::_on_bt_instance_updated(int _status, uint64_t p_instance_id) { if (p_instance_id != tracked_instance_id) { return; } BTInstance *inst = Object::cast_to(OBJECT_DB_GET_INSTANCE(p_instance_id)); ERR_FAIL_NULL(inst); Array arr = BehaviorTreeData::serialize(inst); EngineDebugger::get_singleton()->send_message("limboai:bt_update", arr); } #endif // ! DEBUG_ENABLED