Skip to content

Commit 1eb3de7

Browse files
author
Bytekeeper
committed
Behavior tree documentation
1 parent fdfe190 commit 1eb3de7

22 files changed

+342
-8
lines changed

src/main/java/org/bk/ass/bt/AcquireLock.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
import org.bk.ass.manage.Lock;
44

5+
/**
6+
* Leaf node that will succeed if the supplied lock can be acquired. Fails otherwise.
7+
*
8+
* @param <T> the lock kind
9+
*/
510
public class AcquireLock<T> extends TreeNode {
611

712
private final Lock<T> lock;

src/main/java/org/bk/ass/bt/BehaviorTree.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,30 @@
22

33
import static java.util.Objects.requireNonNull;
44

5+
/**
6+
* A behavior tree. Main difference to other compound nodes is that the actual root tree node is
7+
* constructed on initialization.
8+
* <p/>
9+
* This allows data oriented programming, with simplified access to some data:
10+
* <pre>
11+
* {@code
12+
* public class MyTree extends BehaviorTree {
13+
* // Data shared by nodes of this tree
14+
* private Data myData = new Data(...);
15+
* protected TreeNode getRoot() {
16+
* return new Sequence(new SomeCondition(myData), new Action(myData));
17+
* }
18+
* }
19+
* }
20+
* </pre>
21+
*/
522
public abstract class BehaviorTree extends TreeNode {
623

724
private TreeNode root;
825

26+
/**
27+
* Will be called <em>once</em> to create the actual root to be ticked.
28+
*/
929
protected abstract TreeNode getRoot();
1030

1131
@Override

src/main/java/org/bk/ass/bt/CompoundNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import java.util.Comparator;
66
import java.util.List;
77

8+
/**
9+
* Base class for non-leaf nodes. Usually not subclassed directly.
10+
*/
811
public abstract class CompoundNode extends TreeNode {
12+
913
protected static final Comparator<TreeNode> UTILITY_COMPARATOR =
1014
Comparator.comparing(TreeNode::getUtility).reversed();
1115
protected final List<TreeNode> children;

src/main/java/org/bk/ass/bt/Condition.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import java.util.Objects;
44
import java.util.function.BooleanSupplier;
55

6+
/**
7+
* Node that will succeed if the given check passed, fails otherwise.
8+
*/
69
public class Condition extends TreeNode {
10+
711
private final BooleanSupplier check;
812

913
public Condition(BooleanSupplier check) {

src/main/java/org/bk/ass/bt/Decorator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
import java.util.Objects;
44

5+
/**
6+
* Base class for nodes that delegate execution and modify the delegate or the status.
7+
*/
58
public abstract class Decorator extends TreeNode {
9+
610
private final TreeNode delegate;
711

812
public Decorator(TreeNode delegate) {

src/main/java/org/bk/ass/bt/Distributor.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
import org.bk.ass.StopWatch;
1515
import org.bk.ass.bt.Parallel.Policy;
1616

17+
/**
18+
* This is like <code>map</code> for streams. Maps each item of a given list to a node. New nodes
19+
* will only be created for new items. Nodes for items that are no longer present will be aborted
20+
* and discarded.
21+
* <p/>
22+
* The created child nodes will be executed in parallel in the order of the item list.
23+
*
24+
* @param <T> the type of the item used to create new nodes
25+
*/
1726
public class Distributor<T> extends TreeNode {
1827

1928
private Policy policy;

src/main/java/org/bk/ass/bt/ExecutionContext.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import java.util.List;
88
import java.util.Map;
99

10+
/**
11+
* Can be used to create tree stack traces and log performance numbers of nodes.
12+
*/
1013
public class ExecutionContext {
1114

1215
public static final ExecutionContext NOOP =

src/main/java/org/bk/ass/bt/Inverter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.bk.ass.bt;
22

3+
/**
4+
* Delegates execution but returns the inverted status (ie. failed -> success; success -> failed;
5+
* running -> running).
6+
*/
37
public class Inverter extends Decorator {
48

59
public Inverter(TreeNode delegate) {

src/main/java/org/bk/ass/bt/LambdaNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
import java.util.function.Supplier;
44

5+
/**
6+
* Allows inline nodes using lambdas.
7+
*/
58
public class LambdaNode extends TreeNode {
9+
610
private final Supplier<NodeStatus> delegate;
711

812
public LambdaNode(Supplier<NodeStatus> delegate) {

src/main/java/org/bk/ass/bt/Memo.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package org.bk.ass.bt;
22

3+
/**
4+
* Most nodes of <pre>ASS</pre> are reactive (they will execute no matter what the last execution
5+
* result was). Using this class, once the delegate reaches a non-running status the result will be
6+
* remembered. Further invocations will not change the status and the delegate will not be ticked
7+
* again.
8+
*/
39
public class Memo extends Decorator {
410

511
public Memo(TreeNode delegate) {

src/main/java/org/bk/ass/bt/NodeStatus.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
package org.bk.ass.bt;
22

3+
/**
4+
* Status of a node.
5+
*/
36
public enum NodeStatus {
7+
/**
8+
* Initial status of a node or a resetted node.
9+
*/
410
INITIAL,
11+
/**
12+
* Node did not fail, but also has not completed its task yet.
13+
*/
514
RUNNING,
15+
/**
16+
* Node is done, but can still be ticked and change its status.
17+
*/
618
SUCCESS,
19+
/**
20+
* Node has failed, but can still be ticked and change its status.
21+
*/
722
FAILURE,
8-
/** Child was in state RUNNING but will not be called again due to a parent having completed. */
23+
/**
24+
* Child was in state RUNNING but will not be ticked again due to a parent having completed.
25+
*/
926
ABORTED {
1027
@Override
1128
public TreeNode after(Runnable block) {
1229
throw new UnsupportedOperationException("Abort should not be used this way.");
1330
}
1431
};
1532

33+
/**
34+
* Executes the given code block but will return this NodeStatus' value.
35+
*/
1636
public TreeNode after(Runnable block) {
1737
return new LambdaNode(
1838
() -> {

src/main/java/org/bk/ass/bt/Parallel.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ public class Parallel extends CompoundNode {
1212
private final Policy policy;
1313

1414
public enum Policy {
15+
/**
16+
* Run all children in order, stop if one has {@link NodeStatus#FAILURE}
17+
*/
1518
SEQUENCE,
19+
/**
20+
* Run all children in order, stop if one has {@link NodeStatus#SUCCESS}
21+
*/
1622
SELECTOR
1723
}
1824

src/main/java/org/bk/ass/bt/Repeat.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,38 @@
22

33
import java.util.Objects;
44

5+
/**
6+
* Repeatedly ticks a delegate node. If the delegate completes its operation, it will automatically
7+
* be resetted and re-ticked.
8+
* <p/>
9+
* An internal {@link Policy} is used to determine the status of the Repeat node based on the result
10+
* of the delegate.
11+
* <p/>
12+
* Use {@link Policy#SEQUENCE} to tick a delegate as long as it is succeeding. Use {@link
13+
* Policy#SELECTOR} to tick a delegate until it succeeds. Use {@link Policy#SELECTOR_INVERTED} to
14+
* tick a delegate until it fails.
15+
*/
516
public class Repeat extends Decorator {
17+
618
private final int initialLimit;
719
private int remaining;
820
private final Policy policy;
921

1022
public enum Policy {
23+
/**
24+
* Repeat will have status {@link NodeStatus#RUNNING} while the delegate has status {@link
25+
* NodeStatus#SUCCESS} or {@link NodeStatus#RUNNING}. It will fail otherwise.
26+
*/
1127
SEQUENCE,
28+
/**
29+
* Repeat will have status {@link NodeStatus#RUNNING} while the delegate has status {@link
30+
* NodeStatus#FAILURE} or {@link NodeStatus#RUNNING}. It will succeed otherwise.
31+
*/
1232
SELECTOR,
33+
/**
34+
* Repeat will have status {@link NodeStatus#RUNNING} while the delegate has status {@link
35+
* NodeStatus#SUCCESS} or {@link NodeStatus#RUNNING}. It will succeed otherwise.
36+
*/
1337
SELECTOR_INVERTED
1438
}
1539

src/main/java/org/bk/ass/bt/Succeeder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.bk.ass.bt;
22

33
/**
4-
* Never fails, but
4+
* Never fails, even if the delegate fails.
55
*/
66
public class Succeeder extends Decorator {
77

src/main/java/org/bk/ass/bt/TreeNode.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,106 @@
11
package org.bk.ass.bt;
22

3+
/**
4+
* Base class of all of ASS' behavior trees.
5+
*/
36
public abstract class TreeNode {
47

58
String name = getClass().getSimpleName();
69
NodeStatus status;
710

11+
/**
12+
* Should be called before using this node.
13+
*/
814
public void init() {
915
status = NodeStatus.INITIAL;
1016
}
1117

12-
public void close() {}
18+
/**
19+
* Should be called if this node will not be used again and might perform some operations at the
20+
* end. If used for clean-ups, be aware that some nodes might get {@link #abort()}ed instead and
21+
* will not receive a close call.
22+
*/
23+
public void close() {
24+
}
1325

26+
/**
27+
* Executes this node, with an {@link ExecutionContext} for meta data.
28+
*/
1429
public void exec(ExecutionContext executionContext) {
1530
exec();
1631
}
1732

33+
/**
34+
* Executes this node without any meta data context.
35+
*/
1836
public abstract void exec();
1937

2038
/**
2139
* Used by {@link CompoundNode}s to determine order of execution. Generally, nodes with {@link
2240
* Selector} like behavior will run children in decreasing order of utility. Nodes with {@link
2341
* Sequence} like behavior will not change the order of children unless explicitly stated.
42+
*
43+
* @return 0 by default.
2444
*/
2545
public double getUtility() {
2646
return 0;
2747
}
2848

49+
/**
50+
* Returns the status of the last execution.
51+
*/
2952
public final NodeStatus getStatus() {
3053
return status;
3154
}
3255

56+
/**
57+
* Mark node as successful.
58+
*/
3359
public final void success() {
3460
status = NodeStatus.SUCCESS;
3561
}
3662

63+
/**
64+
* Mark node as running.
65+
*/
3766
public final void running() {
3867
status = NodeStatus.RUNNING;
3968
}
4069

70+
/**
71+
* Mark node as failed.
72+
*/
4173
public final void failed() {
4274
status = NodeStatus.FAILURE;
4375
}
4476

45-
public void reset() {
46-
status = NodeStatus.INITIAL;
47-
}
48-
77+
/**
78+
* Aborts any operation of this node and marks the status as aborted. Subclasses should call
79+
* <pre>super.abort()</pre> on override.
80+
*/
4981
public void abort() {
5082
status = NodeStatus.ABORTED;
5183
}
5284

85+
/**
86+
* Resets the node and its status. If overridden, should always call <pre>super.reset()</pre> to
87+
* ensure status is correct.
88+
*/
89+
public void reset() {
90+
status = NodeStatus.INITIAL;
91+
}
92+
93+
/**
94+
* Sets a name for this node which can be used to identify it in the complete tree.
95+
*/
5396
public final TreeNode withName(String name) {
5497
this.name = name;
5598
return this;
5699
}
57100

101+
/**
102+
* The previously set name.
103+
*/
58104
public String getName() {
59105
return name;
60106
}

src/main/java/org/bk/ass/bt/Wait.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.bk.ass.bt;
22

3+
/**
4+
* Node which always is in status {@link NodeStatus#RUNNING}. Usually used in conjunction with a
5+
* {@link Sequence} and a {@link Condition} to make sure it's not waiting endlessly.
6+
*/
37
public class Wait extends TreeNode {
48

59
public static final Wait INSTANCE = new Wait();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.bk.ass.grid;
2+
3+
public class BooleanGrid extends VersionedGrid<Boolean> {
4+
5+
public BooleanGrid(int width, int height) {
6+
super(width, height);
7+
}
8+
9+
@Override
10+
public Boolean get(int x, int y) {
11+
return dataVersion[y][x] == version;
12+
}
13+
14+
@Override
15+
public void set(int x, int y, Boolean value) {
16+
dataVersion[y][x] = value ? version : 0;
17+
}
18+
19+
@Override
20+
protected Boolean internalGet(int x, int y) {
21+
throw new IllegalStateException("Should not be called");
22+
}
23+
24+
@Override
25+
protected void internalSet(int x, int y, Boolean value) {
26+
throw new IllegalStateException("Should not be called");
27+
}
28+
}

0 commit comments

Comments
 (0)