Current section
Files
Jump to
Current section
Files
src/bt_engine/runners/run_sequence.erl
-module(run_sequence).
-include("../bt_node_behaviours/bt_nodes.hrl").
-export([
run/3,
preempt/3
]).
%% should run each child from left to right; they will return their new states so it will need to update them when returning
%% blackboard will also be changed between each child call
%% if child returns:
%% failure: preempt and then return {failure, NewSequenceNode, NewBB2}
%% running: return {running, NewSequenceNode, NewBB}, preempt all children to the right of running!
%% success: run next child with NewBB; make sure to update this child's state with the returned state
%% all return success: just clear BB and then return {success, NewSequenceNode, NewBB2}
-spec run(SequenceNode :: sequence(), BB :: blackboard(), Event :: event()) -> {Status :: status(), NewSequenceNode :: sequence(), NewBB :: blackboard()}.
run(SequenceNode, BB, Event) when is_record(SequenceNode, sequence) ->
Children = SequenceNode#sequence.children,
{Status, NewChildren, NewBB} = run_children(Children, BB, Event),
case Status of
failure ->
%% clear blackboard and return failure; preemption of children already done.
NewBB2 = bt_blackboard:clear_namespace(SequenceNode#sequence.namespace, BB),
{failure, SequenceNode#sequence{children = NewChildren}, NewBB2};
running ->
%% just return; preemption of children already done.
{running, SequenceNode#sequence{children = NewChildren}, NewBB};
success ->
%% clear blackboard and return success;
NewBB2 = bt_blackboard:clear_namespace(SequenceNode#sequence.namespace, NewBB),
{success, SequenceNode#sequence{children = NewChildren}, NewBB2}
end.
run_children([], BB, _Event) ->
%% all ran successfully! return success
{success, [], BB};
run_children([Child | RestOfChildren], BB, Event) ->
%% run the child
{ChildStatus, NewChildNode, NewBB} = bt_runner:run(Child, BB, Event),
case ChildStatus of
%% failure: preempt all right children
failure ->
{PreemptedRestOfChildren, NewBB2} = preempt_children(RestOfChildren, NewBB, true),
{failure, [NewChildNode | PreemptedRestOfChildren], NewBB2};
%% running: preempt all right children
running ->
{PreemptedRestOfChildren, NewBB2} = preempt_children(RestOfChildren, NewBB, true),
{running, [NewChildNode | PreemptedRestOfChildren], NewBB2};
success ->
%% using the new bb, run the rest of the children
{Status, NewRestOfChildren, NewBB2} = run_children(RestOfChildren, NewBB, Event),
{Status, [NewChildNode | NewRestOfChildren], NewBB2}
end.
%% is being preempted. clear namespace and call preempt on each child.
-spec preempt(SequenceNode :: sequence(), BB :: blackboard(), ShouldCleanBB :: boolean()) -> {NewNode :: term(), NewBB :: blackboard()}.
preempt(SequenceNode, BB, true) ->
%% clear the namespace
NewBB = bt_blackboard:clear_namespace(SequenceNode#sequence.namespace, BB),
%% now dont
preempt(SequenceNode, NewBB, false);
%% don't need to clear the namespace.
preempt(SequenceNode, BB, false) ->
Children = SequenceNode#sequence.children,
{NewChildren, NewBB} = preempt_children(Children, BB, false),
{SequenceNode#sequence{children = NewChildren}, NewBB}.
preempt_children([], BB, _Flag) ->
{[], BB};
preempt_children([Child | RestOfChildren], BB, ShouldCleanBB) ->
{NewChild, NewBB} = bt_runner:preempt(Child, BB, ShouldCleanBB),
{NewRestOfChildren, NewBB2} = preempt_children(RestOfChildren, NewBB, ShouldCleanBB),
{[NewChild | NewRestOfChildren], NewBB2}.