Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating BTSubTree.subtree at runtime #94

Open
onze opened this issue Apr 22, 2024 · 6 comments
Open

Updating BTSubTree.subtree at runtime #94

onze opened this issue Apr 22, 2024 · 6 comments

Comments

@onze
Copy link
Contributor

onze commented Apr 22, 2024

My tree contains a BTSubTree that I want to load dynamically. In order to do this, I leave the subtree field unset, and a sibling custom node does this:

var target_subtree: BTSubtree = find_btask(
	bt_player.get_tree_instance(), 
	my_subtree_task_name
) as BTSubtree
# assert target_subtree != null
target_subtree.subtree = null
var new_btree := ... # roughly load('res://...') as BehaviorTree
target_subtree.subtree = new_btree

In the editor, before this runs, I get the following error:

my_file.gd:95 @ <anonymous lambda>(): Subtree root task is not valid.
  <C++ Error>    Condition "!subtree->get_root_task().is_valid()" is true.
  <C++ Source>   limboai/bt/tasks/decorators/bt_subtree.cpp:33 @ initialize()

And when my code above runs, the task doesn't update properly.

As a workaround, I tried creating a dummy btree and assign it to the BTSubTree, so that the error isn't raised and the subtree can be replaced. It works until I try to set subtree to the new BehaviorTree, which doesn't raise an issue and doesn't update it.

Is this supported?

@onze onze changed the title BTSubTree prints an error for an unset tree before _enter BTSubTree sets itself in a failed state if started without subtree Apr 22, 2024
@onze onze changed the title BTSubTree sets itself in a failed state if started without subtree Updating BTSubTree.subtree at rutime Apr 22, 2024
@onze onze changed the title Updating BTSubTree.subtree at rutime Updating BTSubTree.subtree at runtime Apr 22, 2024
@limbonaut
Copy link
Owner

limbonaut commented Apr 22, 2024

There was a discussion some time ago: #58
It is currently not supported, as BTSubtree is designed to be a simple loader. However, you can do it dynamically, you just need to do it without BTSubtree, either by using a custom decorator, or by walking the tree and inserting your branch where you need it to be. Here's a simple example decorator (written from memory):

extends BTDecorator
## MyCustomBranch

func _setup() -> void:
    var bt: BehaviorTree = load("res://...")
    var my_branch: BTTask = bt.instantiate(agent, blackboard)
    add_child(my_branch)

func _tick(delta) -> Status:
    var child: BTTask = get_child(0)
    return child.execute(delta)

You may or may not want to isolate the blackboard scope for your subtree like this:

var new_scope := Blackboard.new()
new_scope.set_parent(blackboard)
var my_branch: BTTask = bt.instantiate(agent, new_scope)

If your branch utilizes blackboard plan system:

# Using new scope:
var new_scope: Blackboard = bt.blackboard_plan.create_blackboard(agent)
var my_branch: BTTask = bt.instantiate(agent, new_scope)

# Or not using new scope:
bt.blackboard_plan.populate_blackboard(blackboard, false, agent)
var my_branch: BTTask = bt.instantiate(agent, blackboard)

@onze
Copy link
Contributor Author

onze commented Apr 22, 2024

Makes sense, thanks for the quick answer. I opened a PR to add a quick mention to this in BTSubtree's doc itself. Feel free to dismiss it if you feel like it's too much detail.

@speakk
Copy link

speakk commented Sep 4, 2024

The example provided here seems to be quite outdated is bt.instantiate has a different signature now, and also gives an error such as: Cannot assign a value of type BTInstance to variable "my_branch" with specified type BTTask.

I'll see if I can get this working myself (very new with limboAI but need this feature), but otherwise any insight from the creator would be appreciated.

@limbonaut
Copy link
Owner

@speakk Check out the following link. It's an up-to-date example of how to create and manage a BT instance.
https://github.com/limbonaut/limboai-extra/blob/main/examples/custom_bt_player/custom_bt_player.gd

You can also find information about methods in the documentation.

@limbonaut
Copy link
Owner

limbonaut commented Sep 4, 2024

@speakk You probably don't need to create BTInstance for this use-case. Try bt.get_root_task().clone() instead. That should fix that example, I think.

Something like this:

extends BTDecorator
## MyCustomBranch

func _setup() -> void:
    var bt: BehaviorTree = load("res://...")
    var my_branch: BTTask = bt.get_root_task().clone()
    my_branch.initialize(agent, blackboard)
    add_child(my_branch)

func _tick(delta) -> Status:
    var child: BTTask = get_child(0)
    return child.execute(delta)

@speakk
Copy link

speakk commented Sep 4, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants