-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Nikolas Howard
committed
Sep 29, 2023
1 parent
473ace7
commit cf84399
Showing
45 changed files
with
5,173 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { CompleteState } from "./State"; | ||
export type Agent = { | ||
[actionName: string]: AgentFunction; | ||
}; | ||
export type ExitFunctionArg = { | ||
succeeded: boolean; | ||
aborted: boolean; | ||
}; | ||
export type FunctionArg = number | string | boolean | null | ExitFunctionArg; | ||
export type ActionResult = CompleteState | Promise<CompleteState> | boolean; | ||
export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; | ||
export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { AnyArgument } from "./RootAstNodesBuilder"; | ||
import { AnyState } from "./State"; | ||
import Root from "./nodes/decorator/Root"; | ||
import { Agent, GlobalFunction } from "./Agent"; | ||
import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; | ||
import { GuardAttributeDetails } from "./attributes/guards/Guard"; | ||
import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; | ||
export type FlattenedTreeNode = { | ||
id: string; | ||
type: string; | ||
caption: string; | ||
state: AnyState; | ||
guards: GuardAttributeDetails[]; | ||
callbacks: CallbackAttributeDetails[]; | ||
args: AnyArgument[]; | ||
parentId: string | null; | ||
}; | ||
/** | ||
* A representation of a behaviour tree. | ||
*/ | ||
export declare class BehaviourTree { | ||
private agent; | ||
private options; | ||
/** | ||
* The main root tree node. | ||
*/ | ||
readonly rootNode: Root; | ||
/** | ||
* Creates a new instance of the BehaviourTree class. | ||
* @param definition The behaviour tree definition. | ||
* @param agent The agent instance that this behaviour tree is modelling behaviour for. | ||
* @param options The behaviour tree options object. | ||
*/ | ||
constructor(definition: string, agent: Agent, options?: BehaviourTreeOptions); | ||
/** | ||
* Gets whether the tree is in the RUNNING state. | ||
* @returns true if the tree is in the RUNNING state, otherwise false. | ||
*/ | ||
isRunning(): boolean; | ||
/** | ||
* Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING. | ||
* @returns The current tree state. | ||
*/ | ||
getState(): AnyState; | ||
/** | ||
* Step the tree. | ||
* Carries out a node update that traverses the tree from the root node outwards to any child nodes, skipping those that are already in a resolved state of SUCCEEDED or FAILED. | ||
* After being updated, leaf nodes will have a state of SUCCEEDED, FAILED or RUNNING. Leaf nodes that are left in the RUNNING state as part of a tree step will be revisited each | ||
* subsequent step until they move into a resolved state of either SUCCEEDED or FAILED, after which execution will move through the tree to the next node with a state of READY. | ||
* | ||
* Calling this method when the tree is already in a resolved state of SUCCEEDED or FAILED will cause it to be reset before tree traversal begins. | ||
*/ | ||
step(): void; | ||
/** | ||
* Resets the tree from the root node outwards to each nested node, giving each a state of READY. | ||
*/ | ||
reset(): void; | ||
/** | ||
* Gets the flattened details of every node in the tree. | ||
* @returns The flattened details of every node in the tree. | ||
*/ | ||
getFlattenedNodeDetails(): FlattenedTreeNode[]; | ||
/** | ||
* Registers the action/condition/guard/callback function or subtree with the given name. | ||
* @param name The name of the function or subtree to register. | ||
* @param value The function or subtree definition to register. | ||
*/ | ||
static register(name: string, value: GlobalFunction | string): void; | ||
/** | ||
* Unregisters the registered action/condition/guard/callback function or subtree with the given name. | ||
* @param name The name of the registered action/condition/guard/callback function or subtree to unregister. | ||
*/ | ||
static unregister(name: string): void; | ||
/** | ||
* Unregister all registered action/condition/guard/callback functions and subtrees. | ||
*/ | ||
static unregisterAll(): void; | ||
/** | ||
* Parses a behaviour tree definition and creates a tree of behaviour tree nodes. | ||
* @param {string} definition The behaviour tree definition. | ||
* @returns The root behaviour tree node. | ||
*/ | ||
private static _createRootNode; | ||
/** | ||
* Applies a guard path to every leaf of the tree to evaluate as part of each update. | ||
* @param rootNode The main root tree node. | ||
*/ | ||
private static _applyLeafNodeGuardPaths; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* The options object that can be passed as an argument when instantiating the BehaviourTree class. | ||
*/ | ||
export interface BehaviourTreeOptions { | ||
/** | ||
* Gets a delta time in seconds that is used to calculate the elapsed duration of any wait nodes. | ||
* @returns The delta time to use in seconds. | ||
*/ | ||
getDeltaTime?(): number; | ||
/** | ||
* Gets a pseudo-random floating-point number between 0 (inclusive) and 1 (exclusive) for use in the selection of active children for any lotto nodes. | ||
* @returns A floating-point number between 0 (inclusive) and 1 (exclusive) | ||
*/ | ||
random?(): number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { ActionResult, Agent, ExitFunctionArg, GlobalFunction } from "./Agent"; | ||
import { AnyArgument, RootAstNode } from "./RootAstNodesBuilder"; | ||
type ExitResultArg = { | ||
value: ExitFunctionArg; | ||
}; | ||
export type AnyExitArgument = AnyArgument | ExitResultArg; | ||
export type InvokerFunction = (args: AnyExitArgument[]) => ActionResult; | ||
/** | ||
* A singleton used to store and lookup registered functions and subtrees. | ||
*/ | ||
export default class Lookup { | ||
/** | ||
* The object holding any registered functions keyed on function name. | ||
*/ | ||
private static functionTable; | ||
/** | ||
* The object holding any registered sub-trees keyed on tree name. | ||
*/ | ||
private static subtreeTable; | ||
/** | ||
* Gets the function with the specified name. | ||
* @param name The name of the function. | ||
* @returns The function with the specified name. | ||
*/ | ||
static getFunc(name: string): GlobalFunction; | ||
/** | ||
* Sets the function with the specified name for later lookup. | ||
* @param name The name of the function. | ||
* @param func The function. | ||
*/ | ||
static setFunc(name: string, func: GlobalFunction): void; | ||
/** | ||
* Gets the function invoker for the specified agent and function name. | ||
* If a function with the specified name exists on the agent object then it will | ||
* be returned, otherwise we will then check the registered functions for a match. | ||
* @param agent The agent instance that this behaviour tree is modelling behaviour for. | ||
* @param name The function name. | ||
* @returns The function invoker for the specified agent and function name. | ||
*/ | ||
static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null; | ||
/** | ||
* Gets the subtree with the specified name. | ||
* @param name The name of the subtree. | ||
* @returns The subtree with the specified name. | ||
*/ | ||
static getSubtree(name: string): RootAstNode; | ||
/** | ||
* Sets the subtree with the specified name for later lookup. | ||
* @param name The name of the subtree. | ||
* @param subtree The subtree. | ||
*/ | ||
static setSubtree(name: string, subtree: RootAstNode): void; | ||
/** | ||
* Removes the registered function or subtree with the specified name. | ||
* @param name The name of the registered function or subtree. | ||
*/ | ||
static remove(name: string): void; | ||
/** | ||
* Remove all registered functions and subtrees. | ||
*/ | ||
static empty(): void; | ||
} | ||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import Action from "./nodes/leaf/Action"; | ||
import Condition from "./nodes/leaf/Condition"; | ||
import Wait from "./nodes/leaf/Wait"; | ||
import Root from "./nodes/decorator/Root"; | ||
import Repeat from "./nodes/decorator/Repeat"; | ||
import Retry from "./nodes/decorator/Retry"; | ||
import Lotto from "./nodes/composite/Lotto"; | ||
import Node from "./nodes/Node"; | ||
import Attribute from "./attributes/Attribute"; | ||
import Composite from "./nodes/composite/Composite"; | ||
import Decorator from "./nodes/decorator/Decorator"; | ||
import Leaf from "./nodes/leaf/Leaf"; | ||
export type Argument<T> = { | ||
value: T; | ||
type: string; | ||
}; | ||
type NullArgument = Argument<null> & { | ||
type: "null"; | ||
}; | ||
type BooleanArgument = Argument<boolean> & { | ||
type: "boolean"; | ||
}; | ||
type NumberArgument = Argument<number> & { | ||
type: "number"; | ||
isInteger: boolean; | ||
}; | ||
type StringPlaceholderArgument = Argument<string> & { | ||
type: "string"; | ||
}; | ||
type IdentifierArgument = Argument<string> & { | ||
type: "identifier"; | ||
}; | ||
export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; | ||
type Validatable = { | ||
children?: AstNode<Node>[]; | ||
validate: (depth: number) => void; | ||
}; | ||
type NodeInstanceCreator<T extends Node> = (namedRootNodeProvider: (name: string) => RootAstNode, visitedBranches: string[]) => T; | ||
export type AstNode<T extends Node> = Validatable & { | ||
type: string; | ||
createNodeInstance: NodeInstanceCreator<T>; | ||
}; | ||
export type LeafAstNode<T extends Leaf = Leaf> = AstNode<T> & { | ||
type: "action" | "condition" | "wait"; | ||
attributes: Attribute[]; | ||
}; | ||
export type CompositeAstNode<T extends Composite = Composite> = AstNode<T> & { | ||
type: "lotto" | "parallel" | "selector" | "sequence"; | ||
attributes: Attribute[]; | ||
children: AstNode<Node>[]; | ||
}; | ||
export type DecoratorAstNode<T extends Decorator = Decorator> = AstNode<T> & { | ||
type: "fail" | "flip" | "repeat" | "retry" | "root" | "succeed"; | ||
attributes: Attribute[]; | ||
children: AstNode<Node>[]; | ||
}; | ||
export type BranchAstNode = AstNode<Node> & { | ||
type: "branch"; | ||
branchName: "" | string; | ||
}; | ||
export type LottoAstNode = CompositeAstNode<Lotto> & { | ||
type: "lotto"; | ||
tickets: number[]; | ||
}; | ||
export type RootAstNode = DecoratorAstNode<Root> & { | ||
type: "root"; | ||
name: null | string; | ||
}; | ||
export type RepeatAstNode = DecoratorAstNode<Repeat> & { | ||
type: "repeat"; | ||
iterations: number | null; | ||
iterationsMin: number | null; | ||
iterationsMax: number | null; | ||
}; | ||
export type RetryAstNode = DecoratorAstNode<Retry> & { | ||
type: "retry"; | ||
attempts: number | null; | ||
attemptsMin: number | null; | ||
attemptsMax: number | null; | ||
}; | ||
export type ActionAstNode = LeafAstNode<Action> & { | ||
type: "action"; | ||
actionName: string; | ||
actionArguments: AnyArgument[]; | ||
}; | ||
export type ConditionAstNode = LeafAstNode<Condition> & { | ||
type: "condition"; | ||
conditionName: string; | ||
conditionArguments: AnyArgument[]; | ||
}; | ||
export type WaitAstNode = LeafAstNode<Wait> & { | ||
type: "wait"; | ||
duration: number | null; | ||
durationMin: number | null; | ||
durationMax: number | null; | ||
}; | ||
export type AnyAstNode = BranchAstNode | CompositeAstNode | LottoAstNode | DecoratorAstNode | RootAstNode | RepeatAstNode | RetryAstNode | LeafAstNode | ActionAstNode | ConditionAstNode | WaitAstNode; | ||
/** | ||
* Create an array of root AST nodes based on the given definition. | ||
* @param definition The definition to parse the AST nodes from. | ||
* @returns The base definition AST nodes. | ||
*/ | ||
export default function buildRootASTNodes(definition: string): RootAstNode[]; | ||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* Enumeration of node state types. | ||
*/ | ||
export declare enum State { | ||
READY = "mistreevous.ready", | ||
RUNNING = "mistreevous.running", | ||
SUCCEEDED = "mistreevous.succeeded", | ||
FAILED = "mistreevous.failed" | ||
} | ||
export { State as default }; | ||
export type CompleteState = State.SUCCEEDED | State.FAILED; | ||
export type AnyState = State.READY | State.RUNNING | CompleteState; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { AnyArgument } from "../RootAstNodesBuilder"; | ||
import Guard from "./guards/Guard"; | ||
export type AttributeDetails = { | ||
/** The attribute type. */ | ||
type: string; | ||
/** The attribute arguments. */ | ||
args: AnyArgument[]; | ||
}; | ||
/** | ||
* A base node attribute. | ||
*/ | ||
export default abstract class Attribute<TAttributeDetails extends AttributeDetails = AttributeDetails> { | ||
protected type: string; | ||
protected args: AnyArgument[]; | ||
/** | ||
* @param type The node attribute type. | ||
* @param args The array of attribute argument definitions. | ||
*/ | ||
constructor(type: string, args: AnyArgument[]); | ||
/** | ||
* Gets the type of the attribute. | ||
*/ | ||
getType: () => string; | ||
/** | ||
* Gets the array of attribute argument definitions. | ||
*/ | ||
getArguments: () => AnyArgument[]; | ||
/** | ||
* Gets the attribute details. | ||
*/ | ||
abstract getDetails(): TAttributeDetails; | ||
/** | ||
* Gets whether this attribute is a guard. | ||
*/ | ||
abstract isGuard: () => this is Guard; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Agent } from "../../Agent"; | ||
import { AnyArgument } from "../../RootAstNodesBuilder"; | ||
import Attribute, { AttributeDetails } from "../Attribute"; | ||
export type CallbackAttributeDetails = { | ||
/** The name of the agent function that is called. */ | ||
functionName: string; | ||
} & AttributeDetails; | ||
/** | ||
* A base node callback attribute. | ||
*/ | ||
export default abstract class Callback extends Attribute<CallbackAttributeDetails> { | ||
private functionName; | ||
/** | ||
* @param type The node attribute type. | ||
* @param args The array of decorator argument definitions. | ||
* @param functionName The name of the agent function to call. | ||
*/ | ||
constructor(type: string, args: AnyArgument[], functionName: string); | ||
/** | ||
* Gets the name of the agent function to call. | ||
*/ | ||
getFunctionName: () => string; | ||
/** | ||
* Gets whether this attribute is a guard. | ||
*/ | ||
isGuard: () => boolean; | ||
/** | ||
* Gets the attribute details. | ||
*/ | ||
getDetails(): CallbackAttributeDetails; | ||
/** | ||
* Attempt to call the agent function that this callback refers to. | ||
* @param agent The agent. | ||
*/ | ||
abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Callback from "./Callback"; | ||
import { Agent } from "../../Agent"; | ||
import { AnyArgument } from "../../RootAstNodesBuilder"; | ||
/** | ||
* An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state. | ||
*/ | ||
export default class Entry extends Callback { | ||
/** | ||
* @param functionName The name of the agent function to call. | ||
* @param args The array of callback argument definitions. | ||
*/ | ||
constructor(functionName: string, args: AnyArgument[]); | ||
/** | ||
* Attempt to call the agent function that this callback refers to. | ||
* @param agent The agent. | ||
*/ | ||
callAgentFunction: (agent: Agent) => void; | ||
} |
Oops, something went wrong.