Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions addons/beehave/beehave.gdextension
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ BeehaveFailer = "res://addons/beehave/icons/failer.svg"
BeehaveSucceeder = "res://addons/beehave/icons/succeeder.svg"
BeehaveInverter = "res://addons/beehave/icons/inverter.svg"
BeehaveLimiter = "res://addons/beehave/icons/limiter.svg"
BeehaveRepeater = "res://addons/beehave/icons/repeater.svg"
BeehaveTimeLimiter = "res://addons/beehave/icons/limiter.svg"
BeehaveUntilFail = "res://addons/beehave/icons/until_fail.svg"
BeehaveLeaf = "res://addons/beehave/icons/category_leaf.svg"
BeehaveAction = "res://addons/beehave/icons/action.svg"
BeehaveCondition = "res://addons/beehave/icons/condition.svg"
45 changes: 45 additions & 0 deletions addons/beehave/icons/until_fail.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 36 additions & 2 deletions extension/src/nodes/beehave_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,31 @@ BeehaveBlackboard *BeehaveTree::get_blackboard() const {

void BeehaveTree::enable() {
enabled = true;

set_physics_process(enabled && process_thread == ProcessThread::PHYSICS);
set_process(enabled && process_thread == ProcessThread::IDLE);
}

void BeehaveTree::disable() {
enabled = false;

set_physics_process(enabled && process_thread == ProcessThread::PHYSICS);
set_process(enabled && process_thread == ProcessThread::IDLE);

interrupt();
}

void BeehaveTree::set_enabled(bool enabled) {
this->enabled = enabled;

if(enabled) {
enable();
}
else {
disable();
}
}

bool BeehaveTree::is_enabled() const {
return enabled;
}
Expand All @@ -150,6 +166,9 @@ BeehaveTickStatus BeehaveTree::get_tick_status() const {

void BeehaveTree::set_process_thread(BeehaveTree::ProcessThread thread) {
process_thread = thread;

set_physics_process(enabled && process_thread == ProcessThread::PHYSICS);
set_process(enabled && process_thread == ProcessThread::IDLE);
}

BeehaveTree::ProcessThread BeehaveTree::get_process_thread() const {
Expand Down Expand Up @@ -186,9 +205,24 @@ BeehaveTickStatus BeehaveTree::tick() {
continue;
}
BeehaveTreeNode *tree_node = cast_to<BeehaveTreeNode>(child);
if (tree_node) {
tick_status = tree_node->tick(context);
if (tree_node == nullptr) {
// Skip nodes that aren't valid Beehave nodes
continue;
}

if (tick_status != BeehaveTickStatus::RUNNING) {
tree_node->before_run(context);
}

tick_status = tree_node->tick(context);

if (tick_status != BeehaveTickStatus::RUNNING) {
tree_node->after_run(context);
}
}
return tick_status;
}

void BeehaveTree::interrupt() {
// TODO: interrupt currently running child, if it exists
}
1 change: 1 addition & 0 deletions extension/src/nodes/beehave_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class BeehaveTree : public Node {
int get_tick_rate() const;
void set_process_thread(BeehaveTree::ProcessThread thread);
BeehaveTree::ProcessThread get_process_thread() const;
void interrupt();
};

} //namespace godot
Expand Down
15 changes: 15 additions & 0 deletions extension/src/nodes/beehave_tree_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ BeehaveTickStatus BeehaveTreeNode::tick(Ref<BeehaveContext> context) {
return status;
}

void BeehaveTreeNode::interrupt(Ref<BeehaveContext> context) {
GDVIRTUAL_CALL(_interrupt, context);
}

void BeehaveTreeNode::before_run(Ref<BeehaveContext> context) {
GDVIRTUAL_CALL(_before_run, context);
}

void BeehaveTreeNode::after_run(Ref<BeehaveContext> context) {
GDVIRTUAL_CALL(_after_run, context);
}

BeehaveTreeNode* BeehaveTreeNode::cast_node(Node* node) const {
BeehaveTreeNode *tree_node = cast_to<BeehaveTreeNode>(node);
if (!tree_node) {
Expand All @@ -56,6 +68,9 @@ BeehaveTreeNode* BeehaveTreeNode::cast_node(Node* node) const {
void BeehaveTreeNode::_bind_methods() {

GDVIRTUAL_BIND(_tick, "context");
GDVIRTUAL_BIND(_interrupt, "context");
GDVIRTUAL_BIND(_before_run, "context");
GDVIRTUAL_BIND(_after_run, "context");

BIND_ENUM_CONSTANT(PENDING);
BIND_ENUM_CONSTANT(SUCCESS);
Expand Down
12 changes: 12 additions & 0 deletions extension/src/nodes/beehave_tree_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ class BeehaveTreeNode : public Node {
virtual BeehaveTickStatus tick(Ref<BeehaveContext> context);

GDVIRTUAL1RC(BeehaveTickStatus, _tick, Ref<BeehaveContext>);

virtual void interrupt(Ref<BeehaveContext> context);

GDVIRTUAL1C(_interrupt, Ref<BeehaveContext>);

virtual void before_run(Ref<BeehaveContext> context);

GDVIRTUAL1C(_before_run, Ref<BeehaveContext>);

virtual void after_run(Ref<BeehaveContext> context);

GDVIRTUAL1C(_after_run, Ref<BeehaveContext>);
};

} //namespace godot
Expand Down
30 changes: 30 additions & 0 deletions extension/src/nodes/composites/beehave_composite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,34 @@ BeehaveComposite::BeehaveComposite() {

BeehaveComposite::~BeehaveComposite() {

}

void BeehaveComposite::after_run(Ref<BeehaveContext> context) {
running_child = nullptr;
}

void BeehaveComposite::interrupt(Ref<BeehaveContext> context) {
if (running_child) {
running_child->interrupt(context);
running_child = nullptr;
}
BeehaveTreeNode::interrupt(context);
}

void BeehaveComposite::interrupt_children(Ref<BeehaveContext> context, int from_index, int to_index) {
if (from_index >= to_index) {
return;
}

TypedArray<Node> children = get_children();

for (int i = from_index; i < to_index; ++i) {
BeehaveTreeNode *child = cast_node(Object::cast_to<Node>(children[i]));
if (child == nullptr) {
// Skip all children which aren't Beehave nodes
continue;
}

child->interrupt(context);
}
}
14 changes: 14 additions & 0 deletions extension/src/nodes/composites/beehave_composite.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,23 @@ namespace godot {
class BeehaveComposite : public BeehaveTreeNode {
GDCLASS(BeehaveComposite, BeehaveTreeNode);

protected:
BeehaveTreeNode *running_child;

public:
BeehaveComposite();
~BeehaveComposite();

void after_run(Ref<BeehaveContext> context);

void interrupt(Ref<BeehaveContext> context);

protected:
/*
*Interrupt all children between from_index and to_index (non-inclusive)
*For example, `interrupt_children(context, 2, 6)` will interrupt children at indices 2, 3, 4 and 5, but not 6
*/
void interrupt_children(Ref<BeehaveContext> context, int from_index, int to_index);
};
} //namespace godot

Expand Down
57 changes: 56 additions & 1 deletion extension/src/nodes/composites/beehave_selector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,83 @@ void BeehaveSelector::_bind_methods() {

BeehaveTickStatus BeehaveSelector::tick(Ref<BeehaveContext> context) {
TypedArray<Node> children = get_children();
int processed_count = 0;

for (int i = 0; i < children.size(); ++i) {
if (i < last_execution_index) {
// skip everything that was executed already
++processed_count;
continue;
}
BeehaveTreeNode *child = cast_node(Object::cast_to<Node>(children[i]));
if (child == nullptr) {
// skip anything that is not a valid beehave node
continue;
}

if (child != running_child) {
child->before_run(context);
}

BeehaveTickStatus response = child->tick(context);
++processed_count;

switch (response) {
case SUCCESS:
// TODO: introduce after_run mechanism
if (running_child) {
if (running_child != child) {
running_child->interrupt(context);
}
running_child = nullptr;
}
child->after_run(context);
interrupt_children(context, i + 1, previous_success_or_running_index + 1);

previous_success_or_running_index = i;
ready_to_interrupt_all = false;
return SUCCESS;
case FAILURE:
running_child = nullptr;
child->after_run(context);
++last_execution_index;
break;
case RUNNING:
if (child != running_child) {
if (running_child) {
running_child->interrupt(context);
}
running_child = child;
}
interrupt_children(context, i + 1, previous_success_or_running_index + 1);
previous_success_or_running_index = i;
ready_to_interrupt_all = false;
return RUNNING;
}
}

// FIXME: this doesn't account for children that aren't Beehave nodes. In that case, processed_count will never reach children.size()!
// All children failed
ready_to_interrupt_all = (processed_count == children.size());
last_execution_index = 0;
return BeehaveTickStatus::FAILURE;
}

void BeehaveSelector::after_run(Ref<BeehaveContext> context) {
last_execution_index = 0;
BeehaveComposite::after_run(context);
}

void BeehaveSelector::interrupt(Ref<BeehaveContext> context) {
if (ready_to_interrupt_all) {
interrupt_children(context, 0, get_child_count());
ready_to_interrupt_all = false;
}
else {
interrupt_children(context, last_execution_index + 1, previous_success_or_running_index + 1);
}

last_execution_index = 0;
previous_success_or_running_index = -1;

BeehaveComposite::interrupt(context);
}
6 changes: 6 additions & 0 deletions extension/src/nodes/composites/beehave_selector.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class BeehaveSelector : public BeehaveComposite {
GDCLASS(BeehaveSelector, BeehaveComposite);

int last_execution_index = 0;
int previous_success_or_running_index = -1;
bool ready_to_interrupt_all = false;

protected:
static void _bind_methods();
Expand All @@ -47,6 +49,10 @@ class BeehaveSelector : public BeehaveComposite {
~BeehaveSelector();

BeehaveTickStatus tick(Ref<BeehaveContext> context);

void after_run(Ref<BeehaveContext> context);

void interrupt(Ref<BeehaveContext> context);
};
}// namespace godot

Expand Down
26 changes: 24 additions & 2 deletions extension/src/nodes/composites/beehave_selector_random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,47 @@ BeehaveTickStatus BeehaveSelectorRandom::tick(Ref<BeehaveContext> context) {
}

// Since we're going to remove children from the array, iterate it in reverse order.
for (int i = _children_bag.size() -1; i >= 0; --i) {
for (int i = _children_bag.size() - 1; i >= 0; --i) {
BeehaveTreeNode *child = cast_node(Object::cast_to<Node>(_children_bag[i]));
if (child == nullptr) {
// skip anything that is not a valid beehave node
continue;
}

if (child != running_child) {
child->before_run(context);
}

BeehaveTickStatus response = child->tick(context);

switch (response) {
case SUCCESS:
// TODO: introduce after_run mechanism
_children_bag.erase(child);
child->after_run(context);
return SUCCESS;
case FAILURE:
_children_bag.erase(child);
child->after_run(context);
break;
case RUNNING:
if (child != running_child) {
if (running_child) {
running_child->interrupt(context);
}
running_child = child;
}
return RUNNING;
}
}
return BeehaveTickStatus::FAILURE;
}

void BeehaveSelectorRandom::after_run(Ref<BeehaveContext> context) {
_children_bag = get_shuffled_children();
BeehaveCompositeRandom::after_run(context);
}

void BeehaveSelectorRandom::interrupt(Ref<BeehaveContext> context) {
_children_bag = get_shuffled_children();
BeehaveCompositeRandom::interrupt(context);
}
Loading
Loading