Skip to content

Commit

Permalink
doc: migrate wiki to docsify page (#106)
Browse files Browse the repository at this point in the history
Co-authored-by: Josephine Rueckert <[email protected]>
  • Loading branch information
skaldarnar and jdrueckert authored May 25, 2022
1 parent c491071 commit 72e10a3
Show file tree
Hide file tree
Showing 25 changed files with 13,688 additions and 2 deletions.
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,43 @@
# Behaviors
Store for an assortment of behaviors that can be applied to creatures
<div align="center">
<img src="./docs/_media/banner.png">
</div>

_This is a module for [Terasology].
It provides a set of behavior traits that can be applied to creatures and NPCs._

<h2 align="center"><a href="https://terasology.github.io/Behaviors">👉 Documentation 👈</a></h2>

## Contributing

We welcome contributions to our modules, be it bug fixes or feature contributions.
Check out the [Contributor Guide][contributor-guide] on the main project wiki to learn more.

To check out this module (and all its dependencies) to your Terasology workspace run (in the workspace root):

```
groovyw module recurse Behaviors
```

To build a module JAR for just this module run (in the workspace root):

```
gradlew :module:Behaviors:jar
```

To run all tests and static code checks for this module run (in the workspace root):

```
gradlew :module:Behaviors:check
```

### Documentation via gh-pages

The documentation of this module is build with [docsify].
It is served via [gh-pages].
To preview the site you can either use the `docsify` [CLI tool](https://github.com/docsifyjs/docsify-cli) or just run a static server on the `docs` folder.

<!-- References -->
[Terasology]: https://github.com/MovingBlocks/Terasology
[gh-pages]: https://pages.github.com/
[docsify]: https://docsify.js.org/#/
[contributor-guide]: https://github.com/MovingBlocks/Terasology/wiki/Contributor-Quick-Start
Empty file added docs/.nojekyll
Empty file.
74 changes: 74 additions & 0 deletions docs/Action-Nodes-Decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Actions and Decorators

Actions and Decorators are what enables any entity to actually exhibit behavior - they are the 'final' nodes which make an entity do things, and as such will be, alongside with the actual behavior trees, the parts of the Behavior API most useful to someone wishing to give its entity behavior.

## Class Structure

Action and Decorator nodes are implemented by the `ActionNode` and `DecoratorNode` classes, respectively.
Both implement the common `BehaviorNode` interface.

An `ActionNode` is a leaf node and thus has no children

A `DecoratorNode` has strictly one child.

What is important to note is, `ActionNode` and `DecoratorNode` both use an associated `Action` to do their actual work.
For every class with a `@BehaviorAction` annotation, a corresponding ActionNode or DecoratorNode is created, using the specified `Action` class as the action which provides the functionality (and using the `name` specified in the annotation to identify the node in the prefab files).

This means that in order to create a new Action or Decorator, typically _you do not want to create a new Node, but create an `Action` instead._

> [!NOTE|label:Managing State on Actions and Decorators]
>
> In order to save substantially on memory and some performance, every ActionNode and DecoratorNode is created only once for a given behavior tree - these nodes are shared by all Actors running the same tree.
> This means that **storing stateful information in the Action itself is a terrible idea!**
>
> In order to store and read state information, access the `Actor`'s `dataMap` instead, using the Action's `getId()` as an index.
## `Action` and the `@BehaviorAction` annotation

In order to create a new Action or Decorator for use in your behavior trees, you want to create a new class which implements the `Action` interface - extending `BaseAction` is the best way, as you can only focus on the functional parts of the action.

In order for your `Action` to be discovered and loaded by the Behavior system, you need to annotate the class with the `@BehaviorAction` annotation. The format is:

```java
@BehaviorAction(name = "<name-of-your-action>")
```

and if the `Action` is supposed to be used in a Decorator, you add the `isDecorator` parameter:

```java
@BehaviorAction(name = "<name-of-your-decorator", isDecorator = true)
```

### Actions

Actions are leaves - nodes with no children. These typically have an effect on the world or the state of the entity - such as the `move-to`, `set-target-work` or `play-sound` actions.

An Action typically only needs to care about a few things:

- `construct(Actor)`

called when the node is first reached. Useful for setting initial state - don't forget to **[save all state at the actor!](#notyet)**

- `modify(Actor, BehaviorState)`

called each time the node ticks. If the action is somewhat continuous, most of the work will be here. The second argument is irrelevant to an Action.

- `destruct(Actor)`

called on the last tick of the node - when state changes from `RUNNING` to something final.

- `setup()`

a less used method - called right after all the fields are injected when the Action is being created. Can be useful if you need to load something once, but remember - all stateful data needs to be stored at the actor!

### Decorators

Actions designed for use Decorators implement the same methods as Actions designed as Actions, both related to the `DecoratorNode`'s child':

- `modify(Actor, BehaviorState)`

you now care about the second argument, which represents the `BehaviorState` returned by the child node. A Decorator often wants to react to it and/or modify it before returning its own state.

- `prune(Actor)`

called before update, return value decides whether to run child or not. Useful for condition-type nodes.
110 changes: 110 additions & 0 deletions docs/Big-Picture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Big Picture

Here, you can find an overview of some of the inner workings of the Behavior system.

In Terasology, the Behavior system is composed of:

- A Component `Behavior` used for associating entities with behaviors;
- Two components `GroupTag` and `GroupMind` associated with groups;
- An implementation of behavior trees and their related mechanisms (used to describe the behavior of an entity or a group of entities);
- A decorated entity called `Actor`, used to facilitate the process of adding behaviors to a given entity;
- An asset mechanism for loading `.behavior` and `.group` from the assets structure (on disk); and
- An in-game editor for behavior trees (_currently unstable_).

More details on each of the parts can be found below.

## Components

The `Behavior` component is used to associate an existing behavior with an entity or creature.
Behaviors are structured as [behavior trees](Behavior-Trees) and are loaded as assets from [behavior files](Building-a-Behavior-Tree) (`.behavior`).
This component holds two different objects:

- A `BehaviorTree`, deserialized from a behavior file; and
- An `Interpreter`, responsible for evaluating the behavior tree.

The `GroupTag` component is used to assign an entity or creature to a group.
Also, the `GroupMind` component is used in conjunction with `GroupTag` in specific group-related scenarios, where all entities within a group must possess not only the same behavior tree but also the same behavior states (acting in unison).
For more details on how the group mechanism works please see [Groups](Groups).

## Behavior Trees

Behavior trees are the structures used to describe the behavior of an entity within the game.
A behavior is a pre-defined set of actions performed by an entity, triggered by specific conditions or events.
Behaviors can be related to movement (animals wandering in an open field) or more complex actions (searching for water sources to fulfill a specific need).
A graphical illustration of a typical behavior tree is shown below:

<fig src="images/big-picture/bt.png" alt="Example of a Behavior Tree">An example of a behavior tree.</fig>

Behavior trees are composed of different _nodes_, which determine if the behavior will be performed sequentially, or if it will be subject to any conditions.
The illustration above has _sequential_ nodes (right arrows), determining that everything below them will happen in a sequence (from left to right), and _condition_ nodes (question marks), determining that everything below them will happen (in sequence) only if a determined condition is satisfied.

In Terasology, nodes are objects implementing the `TreeNode` interface.
There are composite nodes, action nodes, and decorators, but in an effort not to duplicate information too much, see [Tree Nodes](Tree-Nodes) to learn about the `TreeNode` interface in detail.

Every `Actor` instance (see description below) has an associated `Interpreter`.
That interpreter uses a `BehaviorTreeRunner` (currently `DefaultBehaviorTreeRunner` as we aren't using the bytecode/ASM parts of the system) to work on the given tree - there is a `BehaviorTreeRunner` for every given Actor.
What's important is the `BehaviorTree` is a data class; it provides the underlying tree data, but it's shared between Actors, using the Interpreter/BehaviorTreeRunner combo.

Both `BehaviorTree` and `Interpreter` can also be instantiated and assigned to an entity during gameplay (for example, when entities join a group and must adopt a different behavior).
In this case, the `BehaviorTree` instance is replaced by a new one, while the `Interpreter` can be created as a new instance or it can be replaced by another existing instance (this is particularly important in cases where an entity must not only assume the new behavior but also have its state placed in a specific point within the behavior tree).

## Actor

The Actor is a decorated Entity, a class that facilitates adds Behavior related functionality to a given Entity.
It represents an entity with a behavior.

Important parts of the Actor class:

- `Actor(EntityRef)` constructor - an Actor can only be constructed over a given Entity.
- `getEntity()` - returns the underlying entity.
- `getComponent()`, `getComponentField()`, `hasComponent()` - QoL methods providing easier access to some parts of the underlying entity.
- `save(Component component)` - assigns a component to the current Actor. This method is used when new components are assigned to the Actor, or in some cases when existing components are modified.

Other important parts of the Actor class are:

- `Map<Integer, Object> dataMap`

_Used by every Behavior Node to manipulate its stateful information, so the Nodes themselves can be stateless/reusable.
The `id` arguments used in its related `getValue()` and `setValue()` methods are the tree-unique IDs of the Nodes._

- `Map<String, Object> blackboard`

_Used to facilitate inter-node communication.
While in `dataMap` every node has its own little corner where it stores its info, `blackboard` is the shared space where nodes can co-ordinate any higher level stateful goals._

## Assets

Behaviors are JSON-like files that describe a behavior tree, containing pre-defined elements (nodes) and actions associated with these nodes.
These files (`.behavior`) are located in the `assets/behaviors` folder of each module.

Each entity can have a behavior component included in its `.prefab` file as:

```json
"Behavior" : {
"tree" : "<module>:<behavior>"
}
```

Where `<behavior>` refers to the name of the behavior, and `<module>` refers to the module in which the behavior is defined. You can use any pre-made behavior existing in another module. If you use the `stray` behavior from the Behaviors module, for example, your `.prefab` behavior entry will be:

```json
"Behavior" : {
"tree" : "Behaviors:stray"
}
```

> [!NOTE]
> Although you can omit the `<module>` prefix for behaviors defined in the same module, it is good practice to **always** use the fully qualified name.
>
> This makes it easier to extract and move behaviors to different modules, and it also avoids confusion between behaviors of similar or identical names from different modules.
A curated list of pre-made behaviors can be found [here](Pre-made-Behaviors-and-Nodes).

## GUI Editor

Behavior trees can also be created or edited through the use of the Behavior GUI editor.
The GUI editor is currently unstable, but its latest version can be accessed in-game through the <kbd>F5</kbd> key.

> [!NOTE]
> The UI editor is in a highly experimental state.
> We recommend that you edit your `.behavior` files directly in a text editor of your choice.
114 changes: 114 additions & 0 deletions docs/Building-a-Behavior-Tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Creating a Behavior Tree

Any given behavior tree is specified as a JSON-like asset in the module's `assets/behaviors` folder, with the `.behavior` extension:

<fig src="images/Building-A-Behavior-Tree/behavior-tree-folder.png" alt="Behavior file assets in the module asset file tree">Behavior files are part of a module's assets.</fig>

To create a new tree, just create a `<name>.behavior` file in your module's `assets/behaviors` folder and open it in your favorite text editor.

## Tree file structure

The actual tree definition files have a very simple structure: essentially, the `.behavior` file only represents the definition of the root (top-most) TreeNode, with all of its children/arguments, recursively.
As an example, this is how the file `still.behavior` (originally from the `WildAnimalsMadness` module) is structured:

```yaml
{
sequence:[
{
animation : {
play: "engine:Stand.animationPool",
loop: "engine:Stand.animationPool"
}
},
{
sleep : {
time : 3
}
}
]
}
```

### Nodes - the building blocks

Every TreeNode is required to have a `name`.
That name is pre-defined for the logic / flow control nodes and some special nodes - a reference of which is [here](https://github.com/Terasology/Behaviors/wiki/Control-Flow-Nodes) - and every Action and Decorator node has its name specified by the `name` field in its `BehaviorAction` annotation - more on that [here](Tree-Nodes).

This `name` represents any and every Node in the JSON defining the tree.

#### Simple Nodes, Actions

A simple node with no arguments - which includes most Actions - is represented only by writing down its name:

```yaml
<node-name>
```

#### Nodes with arguments

A node which needs some arguments to be specified needs to be written down as an object:

```yaml
{ <node-name>: { argument-1: value-1, ? <..>
argument-n
: value-n } }
```

In the case of **Decorators** (nodes with strictly 1 child), the child is provided as any other argument, in the form

```yaml
child: <node-definition>
```
where `<node-definition>` can be any arbitrary node, including composite nodes or other Decorators.

#### Composite Nodes

A Composite (multiple-children) node is represented using an array:

```yaml
{ <composite-node-name>: [
<child-node-1>,
<child-node-2>,
<..>
<child-node-3>,
] }
```

```yaml
success
```

> [!NOTE|label:A note on quotes and JSON]
> While the JSON standard disallows keys not wrapped in double quotations, our GSON / deserialization implementation for the most part doesn't care about it - at least in terms of behavior tree files.
> This means that this:
>
> ```yaml
> { sequence: [{ timer: { time: 5 } }, { log: { message: Hello! } }] }
> ```
>
> is virtually identical to this:
>
> ```json
> {
> "sequence": [
> {
> "timer": {"time": 5}
> },
> {
> "log": {"message": "Hello!"}
> }
> ]
> }
> ```
>
> The variant without quotes is a bit more readable and less 'boilerplate-y', but both variants are possible.
>
> _However_, the canonical - quote-infested - version is the only one 100% officially supported, so if you run into issues with the tree file loading, it is a good idea to try if the issue persists with a canonical JSON version of the same tree.
>
> One very handy tool for converting the terse version into canonical JSON is [YAML Parser](http://yaml-online-parser.appspot.com/) - simply paste your tree definition into the left pane, and it spits out canonical JSON on the right.
> It also catches many formatting / syntax errors (but not all, as YAML is a superset of JSON).

## Examples

You can find examples of behavior trees in action [here](Pre-made-Behaviors-and-Nodes).
Loading

0 comments on commit 72e10a3

Please sign in to comment.