/** * bt_task.h * ============================================================================= * Copyright 2021-2023 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. * ============================================================================= */ #ifndef BTTASK_H #define BTTASK_H #ifdef LIMBOAI_MODULE #include "modules/limboai/blackboard/blackboard.h" #include "modules/limboai/util/limbo_task_db.h" #include "core/io/resource.h" #include "core/object/object.h" #include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/vector.h" #include "core/typedefs.h" #include "core/variant/array.h" #include "core/variant/binder_common.h" #include "core/variant/dictionary.h" #include "scene/resources/texture.h" #endif // LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION #include "blackboard/blackboard.h" #include "util/limbo_task_db.h" #include #include #include using namespace godot; #endif // LIMBOAI_GDEXTENSION /** * Base class for BTTask. * Note: In order to properly return Status in the _tick virtual method (GDVIRTUAL1R...) * we must do VARIANT_ENUM_CAST for Status enum before the actual BTTask class declaration. */ class BT : public Resource { GDCLASS(BT, Resource); public: enum Status { FRESH, RUNNING, FAILURE, SUCCESS, }; protected: static void _bind_methods(); }; VARIANT_ENUM_CAST(BT::Status) class BTTask : public BT { GDCLASS(BTTask, BT); private: friend class BehaviorTree; // Avoid namespace pollution in derived classes. struct Data { int index = -1; String custom_name; Node *agent = nullptr; Ref blackboard; BTTask *parent = nullptr; Vector> children; Status status = FRESH; double elapsed = 0.0; } data; Array _get_children() const; void _set_children(Array children); protected: static void _bind_methods(); virtual String _generate_name(); virtual void _setup() {} virtual void _enter() {} virtual void _exit() {} virtual Status _tick(double p_delta) { return FAILURE; } #ifdef LIMBOAI_MODULE GDVIRTUAL0RC(String, _generate_name); GDVIRTUAL0(_setup); GDVIRTUAL0(_enter); GDVIRTUAL0(_exit); GDVIRTUAL1R(Status, _tick, double); GDVIRTUAL0RC(PackedStringArray, _get_configuration_warning); #endif // LIMBOAI_MODULE public: // TODO: GDExtension doesn't have this method hmm... #ifdef LIMBOAI_MODULE virtual bool editor_can_reload_from_file() override { return false; } #endif // LIMBOAI_MODULE _FORCE_INLINE_ Node *get_agent() const { return data.agent; } void set_agent(Node *p_agent) { data.agent = p_agent; } String get_custom_name() const { return data.custom_name; } void set_custom_name(const String &p_name); String get_task_name(); Ref get_root() const; virtual Ref clone() const; virtual void initialize(Node *p_agent, const Ref &p_blackboard); virtual PackedStringArray get_configuration_warnings(); Status execute(double p_delta); void abort(); _FORCE_INLINE_ Ref get_parent() const { return Ref(data.parent); } _FORCE_INLINE_ bool is_root() const { return data.parent == nullptr; } _FORCE_INLINE_ Ref get_blackboard() const { return data.blackboard; } _FORCE_INLINE_ Status get_status() const { return data.status; } _FORCE_INLINE_ double get_elapsed_time() const { return data.elapsed; }; _FORCE_INLINE_ Ref get_child(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, data.children.size(), nullptr); return data.children.get(p_idx); } _FORCE_INLINE_ int get_child_count() const { return data.children.size(); } int get_child_count_excluding_comments() const; void add_child(Ref p_child); void add_child_at_index(Ref p_child, int p_idx); void remove_child(Ref p_child); void remove_child_at_index(int p_idx); _FORCE_INLINE_ bool has_child(const Ref &p_child) const { return data.children.find(p_child) != -1; } _FORCE_INLINE_ int get_index() const { return data.index; } bool is_descendant_of(const Ref &p_task) const; Ref next_sibling() const; void print_tree(int p_initial_tabs = 0); BTTask(); ~BTTask(); }; #endif // BTTASK_H