Compare commits

...

10 Commits

Author SHA1 Message Date
Serhii Snitsaruk 549a595b42
Doc: Fix codeblock broken sphinx 2024-08-05 17:27:43 +02:00
Serhii Snitsaruk a56272a248
Doc: Clarify `LimboState.add_event_handler()` 2024-08-05 17:09:55 +02:00
Serhii Snitsaruk 63de416066
Merge pull request #186 from limbonaut/double-click-to-edit-script
Edit task script on double-click (open help for core task)
2024-08-05 16:54:40 +02:00
Serhii Snitsaruk c19fd54927
Edit task script on double-click (open help for core task) 2024-08-05 16:34:54 +02:00
Serhii Snitsaruk f8c6e83688
Merge pull request #185 from limbonaut/open-builtin-doc
Editor setting to prefer online docs, and open builtin docs by default
2024-08-05 16:29:12 +02:00
Serhii Snitsaruk 5a4893fc53
Editor setting to prefer online docs, and open builtin docs by default 2024-08-05 15:46:02 +02:00
Serhii Snitsaruk 14d8df0858
Merge pull request #184 from limbonaut/custom-scene-root
Allow supplying custom scene root for behavior tree instantiation
2024-08-05 15:18:21 +02:00
Serhii Snitsaruk 868baa470a
Fix documentation errors 2024-08-05 13:34:13 +02:00
Serhii Snitsaruk 319c5787be
Add BTState::set_scene_root_hint() 2024-08-05 13:21:57 +02:00
Serhii Snitsaruk 1e9b321283
Allow setting custom scene root for behavior trees
- Adds new argument to `BehaviorTree.instantiate()`
- Adds `BTPlayer.set_scene_root_hint()` method
2024-08-05 13:03:50 +02:00
19 changed files with 152 additions and 46 deletions

View File

@ -77,13 +77,13 @@ void BehaviorTree::copy_other(const Ref<BehaviorTree> &p_other) {
root_task = p_other->get_root_task();
}
Ref<BTInstance> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner) const {
Ref<BTInstance> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root) const {
ERR_FAIL_COND_V_MSG(root_task == nullptr, nullptr, "BehaviorTree: Instantiation failed - BT has no valid root task.");
ERR_FAIL_NULL_V_MSG(p_agent, nullptr, "BehaviorTree: Instantiation failed - agent can't be null.");
ERR_FAIL_NULL_V_MSG(p_instance_owner, nullptr, "BehaviorTree: Instantiation failed -- instance owner can't be null.");
ERR_FAIL_NULL_V_MSG(p_blackboard, nullptr, "BehaviorTree: Instantiation failed - blackboard can't be null.");
Node *scene_root = p_instance_owner->get_owner();
ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - can't get scene root, because instance_owner not owned by a scene node. Hint: Try my_player.set_owner(get_owner()).");
Node *scene_root = p_custom_scene_root ? p_custom_scene_root : p_instance_owner->get_owner();
ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - unable to establish scene root. This is likely due to the instance owner not being owned by a scene node and custom_scene_root being null.");
Ref<BTTask> root_copy = root_task->clone();
root_copy->initialize(p_agent, p_blackboard, scene_root);
return BTInstance::create(root_copy, get_path(), p_instance_owner);
@ -119,7 +119,7 @@ void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
ClassDB::bind_method(D_METHOD("copy_other", "other"), &BehaviorTree::copy_other);
ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard", "instance_owner"), &BehaviorTree::instantiate);
ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard", "instance_owner", "custom_scene_root"), &BehaviorTree::instantiate, DEFVAL(Variant()));
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");

View File

@ -59,7 +59,7 @@ public:
Ref<BehaviorTree> clone() const;
void copy_other(const Ref<BehaviorTree> &p_other);
Ref<BTInstance> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner) const;
Ref<BTInstance> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_instance_owner, Node *p_custom_scene_root = nullptr) const;
BehaviorTree();
~BehaviorTree();

View File

@ -48,8 +48,9 @@ void BTPlayer::_load_tree() {
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Initialization failed - behavior tree has no valid root task.");
Node *agent = GET_NODE(this, agent_node);
ERR_FAIL_NULL_MSG(agent, vformat("BTPlayer: Initialization failed - can't get agent with path '%s'.", agent_node));
Node *scene_root = get_owner();
ERR_FAIL_NULL_MSG(scene_root, "BTPlayer: Initialization failed - can't get scene root (make sure the BTPlayer's owner property is set).");
Node *scene_root = scene_root_hint ? scene_root_hint : get_owner();
ERR_FAIL_COND_MSG(scene_root == nullptr,
"BTPlayer: Initialization failed - unable to establish scene root. This is likely due to BTPlayer not being owned by a scene node. Check BTPlayer.set_scene_root_hint().");
bt_instance = behavior_tree->instantiate(agent, blackboard, this);
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTPlayer: Failed to instantiate behavior tree.");
#ifdef DEBUG_ENABLED
@ -81,6 +82,15 @@ void BTPlayer::set_bt_instance(const Ref<BTInstance> &p_bt_instance) {
behavior_tree.unref();
}
void BTPlayer::set_scene_root_hint(Node *p_scene_root) {
ERR_FAIL_NULL_MSG(p_scene_root, "BTPlayer: Failed to set scene root hint - scene root is null.");
if (bt_instance.is_valid()) {
ERR_PRINT("BTPlayer: Scene root hint shouldn't be set after the behavior tree is instantiated. This change will not affect the current behavior tree instance.");
}
scene_root_hint = p_scene_root;
}
void BTPlayer::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, &BTPlayer::_update_blackboard_plan))) {
@ -231,6 +241,8 @@ void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTPlayer::get_bt_instance);
ClassDB::bind_method(D_METHOD("set_bt_instance", "bt_instance"), &BTPlayer::set_bt_instance);
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTPlayer::set_scene_root_hint);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent_node"), "set_agent_node", "get_agent_node");
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode");

View File

@ -43,6 +43,7 @@ private:
UpdateMode update_mode = UpdateMode::PHYSICS;
bool active = true;
Ref<Blackboard> blackboard;
Node *scene_root_hint = nullptr;
Ref<BTInstance> bt_instance;
@ -79,6 +80,8 @@ public:
Ref<BTInstance> get_bt_instance() { return bt_instance; }
void set_bt_instance(const Ref<BTInstance> &p_bt_instance);
void set_scene_root_hint(Node *p_scene_root);
BTPlayer();
~BTPlayer();

View File

@ -37,6 +37,13 @@ void BTState::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
_update_blackboard_plan();
}
void BTState::set_scene_root_hint(Node *p_scene_root) {
ERR_FAIL_NULL_MSG(p_scene_root, "BTState: Failed to set scene root hint - scene root is null.");
ERR_FAIL_COND_MSG(bt_instance.is_valid(), "BTState: Scene root hint shouldn't be set after initialization. This change will not affect the current behavior tree instance.");
scene_root_hint = p_scene_root;
}
#ifdef DEBUG_ENABLED
void BTState::_set_monitor_performance(bool p_monitor) {
monitor_performance = p_monitor;
@ -61,10 +68,10 @@ void BTState::_update_blackboard_plan() {
void BTState::_setup() {
LimboState::_setup();
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
Node *scene_root = get_owner();
ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - can't get scene root (make sure the BTState's owner property is set).");
Node *scene_root = scene_root_hint ? scene_root_hint : get_owner();
ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - unable to establish scene root. This is likely due to BTState not being owned by a scene node. Check BTState.set_scene_root_hint().");
bt_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), this);
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - can't instantiate behavior tree.");
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree.");
#ifdef DEBUG_ENABLED
bt_instance->register_with_debugger();
@ -137,6 +144,8 @@ void BTState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_failure_event", "event"), &BTState::set_failure_event);
ClassDB::bind_method(D_METHOD("get_failure_event"), &BTState::get_failure_event);
ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTState::set_scene_root_hint);
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");

View File

@ -25,6 +25,7 @@ private:
Ref<BTInstance> bt_instance;
StringName success_event;
StringName failure_event;
Node *scene_root_hint = nullptr;
protected:
static void _bind_methods();
@ -50,6 +51,8 @@ public:
void set_failure_event(const StringName &p_failure_event) { failure_event = p_failure_event; }
StringName get_failure_event() const { return failure_event; }
void set_scene_root_hint(Node *p_node);
BTState();
#ifdef DEBUG_ENABLED

View File

@ -55,17 +55,17 @@ Methods
.. table::
:widths: auto
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`clone<class_BehaviorTree_method_clone>`\ (\ ) |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`copy_other<class_BehaviorTree_method_copy_other>`\ (\ other\: :ref:`BehaviorTree<class_BehaviorTree>`\ ) |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BehaviorTree_method_get_root_task>`\ (\ ) |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTInstance<class_BTInstance>` | :ref:`instantiate<class_BehaviorTree_method_instantiate>`\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``\ ) |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_root_task<class_BehaviorTree_method_set_root_task>`\ (\ task\: :ref:`BTTask<class_BTTask>`\ ) |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`clone<class_BehaviorTree_method_clone>`\ (\ ) |const| |
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`copy_other<class_BehaviorTree_method_copy_other>`\ (\ other\: :ref:`BehaviorTree<class_BehaviorTree>`\ ) |
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BehaviorTree_method_get_root_task>`\ (\ ) |const| |
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTInstance<class_BTInstance>` | :ref:`instantiate<class_BehaviorTree_method_instantiate>`\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``, custom_scene_root\: ``Node`` = null\ ) |const| |
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_root_task<class_BehaviorTree_method_set_root_task>`\ (\ task\: :ref:`BTTask<class_BTTask>`\ ) |
+-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator
@ -172,9 +172,11 @@ Returns the root task of the BehaviorTree resource.
.. rst-class:: classref-method
:ref:`BTInstance<class_BTInstance>` **instantiate**\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``\ ) |const| :ref:`🔗<class_BehaviorTree_method_instantiate>`
:ref:`BTInstance<class_BTInstance>` **instantiate**\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``, custom_scene_root\: ``Node`` = null\ ) |const| :ref:`🔗<class_BehaviorTree_method_instantiate>`
Instantiates the behavior tree and returns :ref:`BTInstance<class_BTInstance>`. ``instance_owner`` should be the scene node that will own the behavior tree instance. This is typically a :ref:`BTPlayer<class_BTPlayer>`, :ref:`BTState<class_BTState>`, or a custom player node that controls the behavior tree execution. Make sure to pass a :ref:`Blackboard<class_Blackboard>` with values populated from :ref:`blackboard_plan<class_BehaviorTree_property_blackboard_plan>`. See also ``BlackboardPlan.populate_blackboard`` & ``BlackboardPlan.create_blackboard``.
Instantiates the behavior tree and returns :ref:`BTInstance<class_BTInstance>`. ``instance_owner`` should be the scene node that will own the behavior tree instance. This is typically a :ref:`BTPlayer<class_BTPlayer>`, :ref:`BTState<class_BTState>`, or a custom player node that controls the behavior tree execution. Make sure to pass a :ref:`Blackboard<class_Blackboard>` with values populated from :ref:`blackboard_plan<class_BehaviorTree_property_blackboard_plan>`. See also :ref:`BlackboardPlan.populate_blackboard<class_BlackboardPlan_method_populate_blackboard>` & :ref:`BlackboardPlan.create_blackboard<class_BlackboardPlan_method_create_blackboard>`.
If ``custom_scene_root`` is not ``null``, it will be used as the scene root for the newly instantiated behavior tree; otherwise, the scene root will be set to ``instance_owner.owner``. Scene root is essential for :ref:`BBNode<class_BBNode>` instances to work properly.
.. rst-class:: classref-item-separator

View File

@ -62,6 +62,8 @@ Methods
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_bt_instance<class_BTPlayer_method_set_bt_instance>`\ (\ bt_instance\: :ref:`BTInstance<class_BTInstance>`\ ) |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_scene_root_hint<class_BTPlayer_method_set_scene_root_hint>`\ (\ scene_root\: ``Node``\ ) |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`update<class_BTPlayer_method_update>`\ (\ delta\: ``float``\ ) |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
@ -297,7 +299,19 @@ Resets the behavior tree's execution. Each running task will be aborted and the
|void| **set_bt_instance**\ (\ bt_instance\: :ref:`BTInstance<class_BTInstance>`\ ) :ref:`🔗<class_BTPlayer_method_set_bt_instance>`
Sets the :ref:`BTInstance<class_BTInstance>` to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also :ref:`BehaviorTree.instantiate<class_BehaviorTree_property_instantiate>`.
Sets the :ref:`BTInstance<class_BTInstance>` to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also :ref:`BehaviorTree.instantiate<class_BehaviorTree_method_instantiate>`.
.. rst-class:: classref-item-separator
----
.. _class_BTPlayer_method_set_scene_root_hint:
.. rst-class:: classref-method
|void| **set_scene_root_hint**\ (\ scene_root\: ``Node``\ ) :ref:`🔗<class_BTPlayer_method_set_scene_root_hint>`
Sets the ``Node`` that will be used as the scene root for the newly instantiated behavior tree. Should be called before the **BTPlayer** is added to the scene tree (before ``NOTIFICATION_READY``). This is typically useful when creating **BTPlayer** nodes dynamically from code.
.. rst-class:: classref-item-separator

View File

@ -47,9 +47,11 @@ Methods
.. table::
:widths: auto
+-------------------------------------+----------------------------------------------------------------------------+
| :ref:`BTInstance<class_BTInstance>` | :ref:`get_bt_instance<class_BTState_method_get_bt_instance>`\ (\ ) |const| |
+-------------------------------------+----------------------------------------------------------------------------+
+-------------------------------------+---------------------------------------------------------------------------------------------------+
| :ref:`BTInstance<class_BTInstance>` | :ref:`get_bt_instance<class_BTState_method_get_bt_instance>`\ (\ ) |const| |
+-------------------------------------+---------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_scene_root_hint<class_BTState_method_set_scene_root_hint>`\ (\ scene_root\: ``Node``\ ) |
+-------------------------------------+---------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator
@ -136,6 +138,18 @@ Method Descriptions
Returns the behavior tree instance.
.. rst-class:: classref-item-separator
----
.. _class_BTState_method_set_scene_root_hint:
.. rst-class:: classref-method
|void| **set_scene_root_hint**\ (\ scene_root\: ``Node``\ ) :ref:`🔗<class_BTState_method_set_scene_root_hint>`
Sets the ``Node`` that will be used as the scene root for the newly instantiated behavior tree. Should be called before the state machine is initialized. This is typically useful when creating **BTState** nodes dynamically from code.
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`

View File

@ -270,7 +270,13 @@ Called during the update. Implement your state's behavior with this method.
|void| **add_event_handler**\ (\ event\: ``StringName``, handler\: ``Callable``\ ) :ref:`🔗<class_LimboState_method_add_event_handler>`
Registers a ``handler`` to be called when ``event`` is dispatched.
Registers a ``handler`` to be called when ``event`` is dispatched. The handler function should have the following signature:
::
func my_event_handler(cargo=null) -> void:
Cargo is an optional parameter that can be passed to the handler. See also :ref:`dispatch<class_LimboState_method_dispatch>`.
.. rst-class:: classref-item-separator

View File

@ -26,7 +26,14 @@
<return type="void" />
<param index="0" name="bt_instance" type="BTInstance" />
<description>
Sets the [BTInstance] to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also [member BehaviorTree.instantiate].
Sets the [BTInstance] to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also [method BehaviorTree.instantiate].
</description>
</method>
<method name="set_scene_root_hint">
<return type="void" />
<param index="0" name="scene_root" type="Node" />
<description>
Sets the [Node] that will be used as the scene root for the newly instantiated behavior tree. Should be called before the [BTPlayer] is added to the scene tree (before [code]NOTIFICATION_READY[/code]). This is typically useful when creating [BTPlayer] nodes dynamically from code.
</description>
</method>
<method name="update">

View File

@ -15,6 +15,13 @@
Returns the behavior tree instance.
</description>
</method>
<method name="set_scene_root_hint">
<return type="void" />
<param index="0" name="scene_root" type="Node" />
<description>
Sets the [Node] that will be used as the scene root for the newly instantiated behavior tree. Should be called before the state machine is initialized. This is typically useful when creating [BTState] nodes dynamically from code.
</description>
</method>
</methods>
<members>
<member name="behavior_tree" type="BehaviorTree" setter="set_behavior_tree" getter="get_behavior_tree">

View File

@ -39,8 +39,10 @@
<param index="0" name="agent" type="Node" />
<param index="1" name="blackboard" type="Blackboard" />
<param index="2" name="instance_owner" type="Node" />
<param index="3" name="custom_scene_root" type="Node" default="null" />
<description>
Instantiates the behavior tree and returns [BTInstance]. [param instance_owner] should be the scene node that will own the behavior tree instance. This is typically a [BTPlayer], [BTState], or a custom player node that controls the behavior tree execution. Make sure to pass a [Blackboard] with values populated from [member blackboard_plan]. See also [BlackboardPlan.populate_blackboard] &amp; [BlackboardPlan.create_blackboard].
Instantiates the behavior tree and returns [BTInstance]. [param instance_owner] should be the scene node that will own the behavior tree instance. This is typically a [BTPlayer], [BTState], or a custom player node that controls the behavior tree execution. Make sure to pass a [Blackboard] with values populated from [member blackboard_plan]. See also [method BlackboardPlan.populate_blackboard] &amp; [method BlackboardPlan.create_blackboard].
If [param custom_scene_root] is not [code]null[/code], it will be used as the scene root for the newly instantiated behavior tree; otherwise, the scene root will be set to [code]instance_owner.owner[/code]. Scene root is essential for [BBNode] instances to work properly.
</description>
</method>
<method name="set_root_task">

View File

@ -41,7 +41,11 @@
<param index="0" name="event" type="StringName" />
<param index="1" name="handler" type="Callable" />
<description>
Registers a [param handler] to be called when [param event] is dispatched.
Registers a [param handler] to be called when [param event] is dispatched. The handler function should have the following signature:
[codeblock]
func my_event_handler(cargo=null) -> void:
[/codeblock]
Cargo is an optional parameter that can be passed to the handler. See also [method dispatch].
</description>
</method>
<method name="call_on_enter">

View File

@ -776,6 +776,17 @@ void LimboAIEditor::_on_tree_task_selected(const Ref<BTTask> &p_task) {
EDIT_RESOURCE(p_task);
}
void LimboAIEditor::_on_tree_task_activated() {
Ref<BTTask> selected = task_tree->get_selected();
ERR_FAIL_COND(selected.is_null());
Ref<Script> scr = selected->get_script();
if (scr.is_valid()) {
EDIT_SCRIPT(scr->get_path());
} else {
LimboUtility::get_singleton()->open_doc_class(selected->get_class());
}
}
void LimboAIEditor::_on_visibility_changed() {
if (task_tree->is_visible_in_tree()) {
Ref<BTTask> sel = task_tree->get_selected();
@ -1364,7 +1375,7 @@ void LimboAIEditor::_notification(int p_what) {
task_tree->connect("rmb_pressed", callable_mp(this, &LimboAIEditor::_on_tree_rmb));
task_tree->connect("task_selected", callable_mp(this, &LimboAIEditor::_on_tree_task_selected));
task_tree->connect("task_dragged", callable_mp(this, &LimboAIEditor::_on_task_dragged));
task_tree->connect("task_activated", callable_mp(this, &LimboAIEditor::_action_selected).bind(ACTION_RENAME));
task_tree->connect("task_activated", callable_mp(this, &LimboAIEditor::_on_tree_task_activated));
task_tree->connect("probability_clicked", callable_mp(this, &LimboAIEditor::_action_selected).bind(ACTION_EDIT_PROBABILITY));
task_tree->connect("visibility_changed", callable_mp(this, &LimboAIEditor::_on_visibility_changed));
task_tree->connect("visibility_changed", callable_mp(this, &LimboAIEditor::_update_banners));
@ -1434,12 +1445,13 @@ LimboAIEditor::LimboAIEditor() {
plugin = nullptr;
idx_history = 0;
#ifdef LIMBOAI_MODULE
EDITOR_DEF("limbo_ai/editor/prefer_online_documentation", false);
EDITOR_DEF("limbo_ai/editor/layout", 0);
#ifdef LIMBOAI_MODULE
EDITOR_SETTINGS()->add_property_hint(PropertyInfo(Variant::INT, "limbo_ai/editor/layout", PROPERTY_HINT_ENUM, "Classic:0,Widescreen Optimized:1"));
EDITOR_SETTINGS()->set_restart_if_changed("limbo_ai/editor/layout", true);
#elif LIMBOAI_GDEXTENSION
EDITOR_SETTINGS()->set_initial_value("limbo_ai/editor/layout", 0, false);
Dictionary pinfo;
pinfo["name"] = "limbo_ai/editor/layout";
pinfo["type"] = Variant::INT;

View File

@ -229,6 +229,7 @@ private:
void _update_probability_edit();
void _probability_popup_closed();
void _on_tree_task_selected(const Ref<BTTask> &p_task);
void _on_tree_task_activated();
void _on_visibility_changed();
void _on_header_pressed();
void _on_save_pressed();

View File

@ -210,7 +210,7 @@ Variant VARIANT_DEFAULT(Variant::Type p_type) {
#ifdef TOOLS_ENABLED
void SHOW_DOC(const String &p_topic) {
void SHOW_BUILTIN_DOC(const String &p_topic) {
#ifdef LIMBOAI_MODULE
ScriptEditor::get_singleton()->goto_help(p_topic);
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);

View File

@ -114,6 +114,7 @@ using namespace godot;
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox))
#define GET_NODE(m_parent, m_path) m_parent->get_node_internal(m_path)
#define OBJECT_DB_GET_INSTANCE(m_id) ObjectDB::get_instance(m_id)
#define EDITOR_DEF(m_setting, m_value) EditorInterface::get_singleton()->get_editor_settings()->set_initial_value(m_setting, m_value, false)
_FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) {
return Variant(p_obj).has_key(p_prop);
@ -172,7 +173,7 @@ Variant VARIANT_DEFAULT(Variant::Type p_type);
#ifdef TOOLS_ENABLED
void SHOW_DOC(const String &p_topic);
void SHOW_BUILTIN_DOC(const String &p_topic);
void EDIT_SCRIPT(const String &p_path);
#endif // TOOLS_ENABLED

View File

@ -25,6 +25,7 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#endif // TOOLS_ENABLED
#endif // ! LIMBOAI_MODULE
@ -569,33 +570,41 @@ Ref<Shortcut> LimboUtility::get_shortcut(const String &p_path) const {
return nullptr;
}
inline void _open_online_doc_page(const String &p_page) {
OS::get_singleton()->shell_open(vformat("%s/%s", LIMBOAI_VERSION_DOC_URL, p_page));
}
void LimboUtility::open_doc_introduction() {
OS::get_singleton()->shell_open(vformat("%s/getting-started/introduction.html", LIMBOAI_VERSION_DOC_URL));
_open_online_doc_page("getting-started/introduction.html");
}
void LimboUtility::open_doc_online() {
OS::get_singleton()->shell_open(vformat("%s/index.html", LIMBOAI_VERSION_DOC_URL));
_open_online_doc_page("index.html");
}
void LimboUtility::open_doc_gdextension_limitations() {
OS::get_singleton()->shell_open(vformat("%s/getting-started/gdextension.html#limitations-of-the-gdextension-version", LIMBOAI_VERSION_DOC_URL));
_open_online_doc_page("getting-started/gdextension.html#limitations-of-the-gdextension-version");
}
void LimboUtility::open_doc_custom_tasks() {
OS::get_singleton()->shell_open(vformat("%s/getting-started/custom-tasks.html", LIMBOAI_VERSION_DOC_URL));
_open_online_doc_page("getting-started/custom-tasks.html");
}
void LimboUtility::open_doc_class(const String &p_class_name) {
if (p_class_name.begins_with("res://")) {
SHOW_DOC(vformat("class_name:\"%s\"", p_class_name));
// ! FIXME: Opening script documentation is unreliable in Godot, because script
// ! documentation is only parsed when script is re-saved in the script editor.
// ! Workaround: Opening script in the editor instead...
EDIT_SCRIPT(p_class_name);
// SHOW_DOC(vformat("class_name:\"%s\"", p_class_name.trim_prefix("res://")));
return;
}
#ifdef LIMBOAI_MODULE
SHOW_DOC("class_name:" + p_class_name);
#elif LIMBOAI_GDEXTENSION
OS::get_singleton()->shell_open(vformat("%s/classes/class_%s.html", LIMBOAI_VERSION_DOC_URL, p_class_name.to_lower()));
#endif
if (EDITOR_GET("limbo_ai/editor/prefer_online_documentation")) {
_open_online_doc_page(vformat("classes/class_%s.html", p_class_name.to_lower()));
} else {
SHOW_BUILTIN_DOC("class_name:" + p_class_name);
}
}
#endif // ! TOOLS_ENABLED