Compare commits

...

8 Commits

Author SHA1 Message Date
Serhii Snitsaruk 5ddc43fe94
Merge pull request #215 from limbonaut/prefetch-with-base-plan
Prefetch nodes set directly in the BehaviorTree's BlackboardPlan
2024-09-15 17:06:55 +02:00
Serhii Snitsaruk 601aed3684
Merge pull request #216 from limbonaut/gha-debug-builds
GHA: Add an option to create GDExtension debug builds
2024-09-15 16:23:08 +02:00
Serhii Snitsaruk 0e4c06f3b8
Update class docs 2024-09-15 15:47:22 +02:00
Serhii Snitsaruk ac2d734122
Use different prefetch root for the base plan in BTPlayer and BTState 2024-09-15 15:47:11 +02:00
Serhii Snitsaruk 1ca1154cd0
Merge pull request #214 from limbonaut/fix-warnings
Fix loop variables used as copy
2024-09-15 14:36:36 +02:00
Serhii Snitsaruk a8a0f24492
BlackboardPlan: Allow passing different prefetch root for the base plan 2024-09-15 14:16:54 +02:00
Serhii Snitsaruk 50e9e570dd
Fix loop variables used as copy 2024-09-15 13:32:58 +02:00
Serhii Snitsaruk 9032ca0c7b
GHA: Add an option to create GDExtension debug builds 2024-09-09 13:53:42 +02:00
14 changed files with 71 additions and 48 deletions

View File

@ -11,7 +11,11 @@ on:
type: string type: string
default: master default: master
test-build: test-build:
description: Should we perform only a limited number of test builds? description: Limit the number of test builds
type: boolean
default: false
debug-symbols:
description: Build with debug symbols
type: boolean type: boolean
default: false default: false
@ -26,14 +30,18 @@ on:
type: string type: string
default: master default: master
test-build: test-build:
description: Should we perform only a limited number of test builds? description: Limit the number of test builds
type: boolean
default: false
debug-symbols:
description: Build with debug symbols
type: boolean type: boolean
default: false default: false
# Global Settings # Global Settings
env: env:
SCONS_CACHE_LIMIT: 4096 SCONS_CACHE_LIMIT: 4096
SCONSFLAGS: dev_build=no debug_symbols=no SCONSFLAGS: use_mingw=yes dev_build=no
EM_VERSION: 3.1.45 EM_VERSION: 3.1.45
EM_CACHE_FOLDER: "emsdk-cache" EM_CACHE_FOLDER: "emsdk-cache"
GODOT_VERSION: 4.3-stable GODOT_VERSION: 4.3-stable
@ -250,23 +258,25 @@ jobs:
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: ${{github.workspace}}/.scons_cache/ path: ${{github.workspace}}/.scons_cache/
key: ${{env.BIN}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}} key: ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
restore-keys: | restore-keys: |
${{env.BIN}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}} ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}-${{env.LIMBOAI_VERSION}}
${{env.BIN}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}} ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}-${{inputs.limboai-ref}}
${{env.BIN}}-${{inputs.godot-cpp-ref}} ${{env.BIN}}-${{inputs.debug-symbols}}-${{inputs.godot-cpp-ref}}
- name: Compilation - name: Compilation
shell: bash shell: bash
env: env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/ SCONS_CACHE: ${{github.workspace}}/.scons_cache/
DEBUG_FLAGS: ${{ inputs.debug-symbols && 'debug_symbols=yes symbols_visibility=visible' || 'debug_symbols=no' }}
run: | run: |
PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH PATH=${GITHUB_WORKSPACE}/buildroot/bin:$PATH
scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.SCONSFLAGS}} scons platform=${{matrix.opts.platform}} target=${{matrix.opts.target}} arch=${{matrix.opts.arch}} ${{env.DEBUG_FLAGS}} ${{env.SCONSFLAGS}}
- name: Prepare artifact - name: Prepare artifact
shell: bash shell: bash
run: | run: |
ls -R demo/addons/limboai/
mkdir out mkdir out
mv demo/addons/ out/ mv demo/addons/ out/
cp {README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/ cp {README,LICENSE,LOGO_LICENSE}.md out/addons/limboai/

View File

@ -387,33 +387,16 @@ void BlackboardPlan::sync_with_base_plan() {
} }
} }
// Add a variable duplicate to the blackboard, optionally with NodePath prefetch. Ref<Blackboard> BlackboardPlan::create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope, Node *p_prefetch_root_for_base_plan) {
inline void bb_add_var_dup_with_prefetch(const Ref<Blackboard> &p_blackboard, const StringName &p_name, const BBVariable &p_var, bool p_prefetch, Node *p_node) { ERR_FAIL_COND_V(p_prefetch_root == nullptr && prefetch_nodepath_vars, memnew(Blackboard));
if (unlikely(p_prefetch && p_var.get_type() == Variant::NODE_PATH)) {
Node *n = p_node->get_node_or_null(p_var.get_value());
BBVariable var = p_var.duplicate(true);
if (n != nullptr) {
var.set_value(n);
} else {
ERR_PRINT(vformat("BlackboardPlan: Prefetch failed for variable $%s with value: %s", p_name, p_var.get_value()));
var.set_value(Variant());
}
p_blackboard->assign_var(p_name, var);
} else {
p_blackboard->assign_var(p_name, p_var.duplicate(true));
}
}
Ref<Blackboard> BlackboardPlan::create_blackboard(Node *p_node, const Ref<Blackboard> &p_parent_scope) {
ERR_FAIL_COND_V(p_node == nullptr && prefetch_nodepath_vars, memnew(Blackboard));
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
bb->set_parent(p_parent_scope); bb->set_parent(p_parent_scope);
populate_blackboard(bb, true, p_node); populate_blackboard(bb, true, p_prefetch_root, p_prefetch_root_for_base_plan);
return bb; return bb;
} }
void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_node) { void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan) {
ERR_FAIL_COND(p_node == nullptr && prefetch_nodepath_vars); ERR_FAIL_COND(p_prefetch_root == nullptr && prefetch_nodepath_vars);
ERR_FAIL_COND(p_blackboard.is_null()); ERR_FAIL_COND(p_blackboard.is_null());
for (const Pair<StringName, BBVariable> &p : var_list) { for (const Pair<StringName, BBVariable> &p : var_list) {
if (p_blackboard->has_local_var(p.first) && !overwrite) { if (p_blackboard->has_local_var(p.first) && !overwrite) {
@ -429,7 +412,21 @@ void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bo
} }
bool has_mapping = parent_scope_mapping.has(p.first); bool has_mapping = parent_scope_mapping.has(p.first);
bool do_prefetch = !has_mapping && prefetch_nodepath_vars; bool do_prefetch = !has_mapping && prefetch_nodepath_vars;
bb_add_var_dup_with_prefetch(p_blackboard, p.first, p.second, do_prefetch, p_node);
// Add a variable duplicate to the blackboard, optionally with NodePath prefetch.
BBVariable var = p.second.duplicate(true);
if (unlikely(do_prefetch && p.second.get_type() == Variant::NODE_PATH)) {
Node *prefetch_root = !p_prefetch_root_for_base_plan || !is_derived() || is_derived_var_changed(p.first) ? p_prefetch_root : p_prefetch_root_for_base_plan;
Node *n = prefetch_root->get_node_or_null(p.second.get_value());
if (n != nullptr) {
var.set_value(n);
} else {
ERR_PRINT(vformat("BlackboardPlan: Prefetch failed for variable $%s with value: %s", p.first, p.second.get_value()));
var.set_value(Variant());
}
}
p_blackboard->assign_var(p.first, var);
if (has_mapping) { if (has_mapping) {
StringName target_var = parent_scope_mapping[p.first]; StringName target_var = parent_scope_mapping[p.first];
if (target_var != StringName()) { if (target_var != StringName()) {
@ -450,8 +447,8 @@ void BlackboardPlan::_bind_methods() {
ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan);
ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider);
ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider);
ClassDB::bind_method(D_METHOD("create_blackboard", "node", "parent_scope"), &BlackboardPlan::create_blackboard, DEFVAL(Ref<Blackboard>())); ClassDB::bind_method(D_METHOD("create_blackboard", "prefetch_root", "parent_scope", "prefetch_root_for_base_plan"), &BlackboardPlan::create_blackboard, DEFVAL(Ref<Blackboard>()), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "node"), &BlackboardPlan::populate_blackboard); ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "prefetch_root", "prefetch_root_for_base_plan"), &BlackboardPlan::populate_blackboard, DEFVAL(Variant()));
// To avoid cluttering the member namespace, we do not export unnecessary properties in this class. // To avoid cluttering the member namespace, we do not export unnecessary properties in this class.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_prefetch_nodepath_vars", "is_prefetching_nodepath_vars"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_prefetch_nodepath_vars", "is_prefetching_nodepath_vars");

View File

@ -88,9 +88,10 @@ public:
void sync_with_base_plan(); void sync_with_base_plan();
_FORCE_INLINE_ bool is_derived() const { return base.is_valid(); } _FORCE_INLINE_ bool is_derived() const { return base.is_valid(); }
_FORCE_INLINE_ bool is_derived_var_changed(const StringName &p_name) const { return base.is_valid() && var_map.has(p_name) && var_map[p_name].is_value_changed(); }
Ref<Blackboard> create_blackboard(Node *p_agent, const Ref<Blackboard> &p_parent_scope = Ref<Blackboard>()); Ref<Blackboard> create_blackboard(Node *p_prefetch_root, const Ref<Blackboard> &p_parent_scope = Ref<Blackboard>(), Node *p_prefetch_root_for_base_plan = nullptr);
void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_node); void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite, Node *p_prefetch_root, Node *p_prefetch_root_for_base_plan = nullptr);
BlackboardPlan(); BlackboardPlan();
}; };

View File

@ -48,7 +48,7 @@ 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."); 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); 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)); ERR_FAIL_NULL_MSG(agent, vformat("BTPlayer: Initialization failed - can't get agent with path '%s'.", agent_node));
Node *scene_root = scene_root_hint ? scene_root_hint : get_owner(); Node *scene_root = _get_scene_root();
ERR_FAIL_COND_MSG(scene_root == nullptr, 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()."); "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, scene_root); bt_instance = behavior_tree->instantiate(agent, blackboard, this, scene_root);
@ -184,7 +184,7 @@ void BTPlayer::_notification(int p_notification) {
} }
if (blackboard_plan.is_valid()) { if (blackboard_plan.is_valid()) {
// Don't overwrite existing blackboard values as they may be initialized from code. // Don't overwrite existing blackboard values as they may be initialized from code.
blackboard_plan->populate_blackboard(blackboard, false, this); blackboard_plan->populate_blackboard(blackboard, false, this, _get_scene_root());
} }
if (behavior_tree.is_valid()) { if (behavior_tree.is_valid()) {
_load_tree(); _load_tree();

View File

@ -50,6 +50,7 @@ private:
void _load_tree(); void _load_tree();
void _update_blackboard_plan(); void _update_blackboard_plan();
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -65,10 +65,14 @@ void BTState::_update_blackboard_plan() {
} }
} }
Node *BTState::_get_prefetch_root_for_base_plan() {
return _get_scene_root();
}
void BTState::_setup() { void BTState::_setup() {
LimboState::_setup(); LimboState::_setup();
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
Node *scene_root = scene_root_hint ? scene_root_hint : get_owner(); Node *scene_root = _get_scene_root();
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()."); 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, scene_root); bt_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), this, scene_root);
ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree."); ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree.");

View File

@ -28,6 +28,8 @@ private:
Node *scene_root_hint = nullptr; Node *scene_root_hint = nullptr;
bool monitor_performance = false; bool monitor_performance = false;
_FORCE_INLINE_ Node *_get_scene_root() const { return scene_root_hint ? scene_root_hint : get_owner(); }
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -35,6 +37,7 @@ protected:
virtual bool _should_use_new_scope() const override { return true; } virtual bool _should_use_new_scope() const override { return true; }
virtual void _update_blackboard_plan() override; virtual void _update_blackboard_plan() override;
virtual Node *_get_prefetch_root_for_base_plan() override;
virtual void _setup() override; virtual void _setup() override;
virtual void _exit() override; virtual void _exit() override;

View File

@ -60,7 +60,7 @@
<member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan"> <member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan">
Stores and manages variables that will be used in constructing new [Blackboard] instances. Stores and manages variables that will be used in constructing new [Blackboard] instances.
</member> </member>
<member name="monitor_performance" type="bool" setter="_set_monitor_performance" getter="_get_monitor_performance" default="false"> <member name="monitor_performance" type="bool" setter="set_monitor_performance" getter="get_monitor_performance" default="false">
If [code]true[/code], adds a performance monitor to "Debugger-&gt;Monitors" for each instance of this [BTPlayer] node. If [code]true[/code], adds a performance monitor to "Debugger-&gt;Monitors" for each instance of this [BTPlayer] node.
</member> </member>
<member name="update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="BTPlayer.UpdateMode" default="1"> <member name="update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="BTPlayer.UpdateMode" default="1">

View File

@ -30,7 +30,7 @@
<member name="failure_event" type="StringName" setter="set_failure_event" getter="get_failure_event" default="&amp;&quot;failure&quot;"> <member name="failure_event" type="StringName" setter="set_failure_event" getter="get_failure_event" default="&amp;&quot;failure&quot;">
HSM event that will be dispatched when the behavior tree results in [code]FAILURE[/code]. See [method LimboState.dispatch]. HSM event that will be dispatched when the behavior tree results in [code]FAILURE[/code]. See [method LimboState.dispatch].
</member> </member>
<member name="monitor_performance" type="bool" setter="_set_monitor_performance" getter="_get_monitor_performance" default="false"> <member name="monitor_performance" type="bool" setter="set_monitor_performance" getter="get_monitor_performance" default="false">
If [code]true[/code], adds a performance monitor to "Debugger-&gt;Monitors" for each instance of this [BTState] node. If [code]true[/code], adds a performance monitor to "Debugger-&gt;Monitors" for each instance of this [BTState] node.
</member> </member>
<member name="success_event" type="StringName" setter="set_success_event" getter="get_success_event" default="&amp;&quot;success&quot;"> <member name="success_event" type="StringName" setter="set_success_event" getter="get_success_event" default="&amp;&quot;success&quot;">

View File

@ -10,10 +10,11 @@
<methods> <methods>
<method name="create_blackboard"> <method name="create_blackboard">
<return type="Blackboard" /> <return type="Blackboard" />
<param index="0" name="node" type="Node" /> <param index="0" name="prefetch_root" type="Node" />
<param index="1" name="parent_scope" type="Blackboard" default="null" /> <param index="1" name="parent_scope" type="Blackboard" default="null" />
<param index="2" name="prefetch_root_for_base_plan" type="Node" default="null" />
<description> <description>
Constructs a new instance of a [Blackboard] using this plan. If [NodePath] prefetching is enabled, [param node] will be used to retrieve node instances for [NodePath] variables and substitute their values. Constructs a new instance of a [Blackboard] using this plan. If [NodePath] prefetching is enabled, [param prefetch_root] will be used to retrieve node instances for [NodePath] variables and substitute their values.
</description> </description>
</method> </method>
<method name="get_base_plan" qualifiers="const"> <method name="get_base_plan" qualifiers="const">
@ -38,9 +39,10 @@
<return type="void" /> <return type="void" />
<param index="0" name="blackboard" type="Blackboard" /> <param index="0" name="blackboard" type="Blackboard" />
<param index="1" name="overwrite" type="bool" /> <param index="1" name="overwrite" type="bool" />
<param index="2" name="node" type="Node" /> <param index="2" name="prefetch_root" type="Node" />
<param index="3" name="prefetch_root_for_base_plan" type="Node" default="null" />
<description> <description>
Populates [param blackboard] with the variables from this plan. If [param overwrite] is [code]true[/code], existing variables with the same names will be overwritten. If [NodePath] prefetching is enabled, [param node] will be used to retrieve node instances for [NodePath] variables and substitute their values. Populates [param blackboard] with the variables from this plan. If [param overwrite] is [code]true[/code], existing variables with the same names will be overwritten. If [NodePath] prefetching is enabled, [param prefetch_root] will be used to retrieve node instances for [NodePath] variables and substitute their values.
</description> </description>
</method> </method>
<method name="set_base_plan"> <method name="set_base_plan">

View File

@ -43,7 +43,7 @@
<description> <description>
Registers a [param handler] to be called when [param event] is dispatched. The handler function should have the following signature: Registers a [param handler] to be called when [param event] is dispatched. The handler function should have the following signature:
[codeblock] [codeblock]
func my_event_handler(cargo=null) -> bool: func my_event_handler(cargo=null) -&gt; bool:
[/codeblock] [/codeblock]
If the handler returns [code]true[/code], the event will be consumed. Cargo is an optional parameter that can be passed to the handler. See also [method dispatch]. If the handler returns [code]true[/code], the event will be consumed. Cargo is an optional parameter that can be passed to the handler. See also [method dispatch].
</description> </description>

View File

@ -869,7 +869,7 @@ void LimboAIEditor::_on_tasks_dragged(const TypedArray<BTTask> &p_tasks, Ref<BTT
// Remove all tasks first so adding ordering is stable. // Remove all tasks first so adding ordering is stable.
int before_pos = 0; int before_pos = 0;
for (const Ref<BTTask> task : tasks_list) { for (const Ref<BTTask> &task : tasks_list) {
if (task->get_parent() == p_to_task && p_to_pos > task->get_index()) { if (task->get_parent() == p_to_task && p_to_pos > task->get_index()) {
before_pos += 1; before_pos += 1;
} }
@ -883,7 +883,7 @@ void LimboAIEditor::_on_tasks_dragged(const TypedArray<BTTask> &p_tasks, Ref<BTT
} }
// Re-add tasks in later undo action so indexes match the old order. // Re-add tasks in later undo action so indexes match the old order.
for (const Ref<BTTask> task : tasks_list) { for (const Ref<BTTask> &task : tasks_list) {
undo_redo->add_undo_method(task->get_parent().ptr(), LW_NAME(add_child_at_index), task, task->get_index()); undo_redo->add_undo_method(task->get_parent().ptr(), LW_NAME(add_child_at_index), task, task->get_index());
} }

View File

@ -33,6 +33,10 @@ void LimboState::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
void LimboState::_update_blackboard_plan() { void LimboState::_update_blackboard_plan() {
} }
Node *LimboState::_get_prefetch_root_for_base_plan() {
return this;
}
Ref<BlackboardPlan> LimboState::_get_parent_scope_plan() const { Ref<BlackboardPlan> LimboState::_get_parent_scope_plan() const {
BlackboardPlan *parent_plan = nullptr; BlackboardPlan *parent_plan = nullptr;
const LimboState *state = this; const LimboState *state = this;
@ -96,7 +100,7 @@ void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
} }
if (blackboard_plan.is_valid() && !blackboard_plan->is_empty()) { if (blackboard_plan.is_valid() && !blackboard_plan->is_empty()) {
// Don't overwrite existing blackboard values as they may be initialized from code. // Don't overwrite existing blackboard values as they may be initialized from code.
blackboard_plan->populate_blackboard(blackboard, false, this); blackboard_plan->populate_blackboard(blackboard, false, this, _get_prefetch_root_for_base_plan());
} }
_setup(); _setup();

View File

@ -54,6 +54,7 @@ protected:
virtual bool _should_use_new_scope() const { return blackboard_plan.is_valid() || is_root(); } virtual bool _should_use_new_scope() const { return blackboard_plan.is_valid() || is_root(); }
virtual void _update_blackboard_plan(); virtual void _update_blackboard_plan();
virtual Node *_get_prefetch_root_for_base_plan();
virtual void _setup(); virtual void _setup();
virtual void _enter(); virtual void _enter();